I’m working with sveltekit for all my recent projects, and for the last one, I needed to add an emoji picker to a textarea. I searched for a simple solution, and it appears that there is none - or I didn’t find it. So here is what I did. Hopefully, it will help the svelte community:
I choose Picmo as my emoji picker, it’s pretty easy to set up, and it does the job perfectly.
Create the Emoji component 🔗
The first step is to create the Emoji component. Let’s create a $lib/emoji.svelte:
<script>
import { createEventDispatcher } from 'svelte';
import { onMount } from 'svelte';
const dispatch = createEventDispatcher();
onMount(async () => {
const { createPopup } = await import('@picmo/popup-picker');
const trigger = document.querySelector('#emojiTrigger');
const picker = createPopup(
{},
{
referenceElement: trigger,
triggerElement: trigger
}
);
trigger.addEventListener('click', () => {
picker.toggle();
});
picker.addEventListener('emoji:select', (selection) => {
dispatch('change', selection);
});
});
</script>
When the component is mounted, we import the Picmo popup lib. Then we create the Popup object, and we pass the trigger object (the trigger is basically the button you will use to open the popup).
On the click on the trigger, we toggle the picker, and when an emoji is selected, we dispatch the selection to the parent element (i.e.: our main page).
Now we need to catch the new event and add it to our textarea.
Add it to the view 🔗
Here is what I did:
page.svelte:
<script>
import EmojiPicker from '$lib/emoji.svelte';
let message;
function onEmoji(event) {
message = newMessage;
}
</script>
<textarea
bind:value={message}
placeholder="Start writing your post…" />
<button id="emojiTrigger"> </button>
<EmojiPicker on:change={onEmoji} />
<div id="pickerContainer" />
We import the EmojiPicker component and add a “#pickerContainer” to the page. When the EmojiPicker change (when a new emoji is selected), we update the message variable. As the textarea value is bound to the message variable, we just have to update the message to display the emoji!
Add the emoji at the right place 🔗
With the code above the emoji will be added at the end of the text. That’s not what we want. Here is how to fix that.
We will update the onEmoji() function
function onEmoji(event) {
const idxPosition = doGetCaretPosition(document.getElementById('comment'));
let newMessage =
message.slice(0, idxPosition) + event.detail.emoji + message.slice(idxPosition);
$message = newMessage;
}
Instead of adding the emoji at the end of the message, we get the position of the cursor and slice the message in two part and add the emoji inside.
To get the cursor position is used a function doGetCaretPosition():
function doGetCaretPosition(oField) {
// Initialize
var iCaretPos = 0;
// IE Support
if (document.selection) {
// Set focus on the element
oField.focus();
// To get cursor position, get empty selection range
var oSel = document.selection.createRange();
// Move selection start to 0 position
oSel.moveStart('character', -oField.value.length);
// The caret position is selection length
iCaretPos = oSel.text.length;
}
// Firefox support
else if (oField.selectionStart || oField.selectionStart == '0')
iCaretPos =
oField.selectionDirection == 'backward' ? oField.selectionStart : oField.selectionEnd;
// Return results
return iCaretPos;
}
Now you should have a nice emoji picker on your sveltekit page! I hope it helps!
If you have any question, ping me on Twitter