##trix #emojis ๐Ÿ‡ฌ๐Ÿ‡ง

Add Emojis to Trix Editor for Ruby on Rails

Jeanro Krupa

Jeanro Krupa

3 min read
We added a cool feature at Komin.io it's emojis support for rich text editor Trix

To enable that 3 steps:
  1. ย Add an emojis library like emojis-mart
  2. Customize Trix toolbar to toggle the emoji picker
  3. ย When an emojis is selected, add into the editor

Disclaimers:
  • โš ๏ธ Our customisation of Trix editor could be fairly optimize ๐Ÿ˜‚ย 
  • Yes you could do ctrl + cmd + space to toggle the native emojis, but our users are not always tech savy

First lets customize trix toolbar, as mentionned there are probably betters ways to do that. But we basically went into the package to copy the html of the toolbar. We have 2 differents toolbar in our app. One "Long" the other one short for stuff like comments.

Here is a part of the js codeย 

import Trix from 'trix' ;
import translations from "./trix-translations.json"

if (document.documentElement.lang == "fr" ) {
  Trix.config.lang = translations[document.documentElement.lang]
}

Trix.config.toolbar.getDefaultHTML = toolbarDefaultHTML;
document.addEventListener("trix-before-initialize", updateToolbars);

function toolbarDefaultHTML(shorty) {
  return shorty === "true" ? short() : long()
}

function updateToolbars(event) {
  const toolbars = document.querySelectorAll('trix-toolbar');
  toolbars.forEach((toolbar) => (toolbar.innerHTML = Trix.config.toolbar.getDefaultHTML(toolbar.closest('.richtext').dataset.short)));
}

function long() {
  const {lang} = Trix.config;

  return `
  <div class=' w-full h-fit overflow-x-auto' data-controller="emoji-picker">
    <div class='flex w-fit gap-28 h-12 py-1 px-1 rounded-lg bg-gray-100 items-center mb-4 overflow-auto'>
      <div class='flex gap-5 h-full overflow-auto'>
        <div class='relative flex gap-2 h-full items-center justify-start w-fit px-1 py-1'>
          <button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${lang.bold}" tabindex="-1">${lang.bold}</button>
          <button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${lang.italic}" tabindex="-1">${lang.italic}</button>
          <button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${lang.strike}" tabindex="-1">${lang.strike}</button>
          <button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${lang.link}" tabindex="-1">${lang.link}</button>
          <div data-controller="dropdown" class="relative">
            <button type="button" class="trix-button " data-trix-attribute="emoji"  title="${lang.emojis}" data-action="dropdown#toggle click@window->dropdown#hide">๐Ÿ˜€</button>
            <div data-emoji-picker-target="pickerContainer" class="hidden transition transform origin-top-right fixed z-50 ml-12" data-dropdown-target="menu">
            </div>
          </div>
        </div>

.... other elements.... 
    </div>
  </div>

  `
You can see the `emoji-picker` controller references that we will add later. We use for the the dropdown tailwind-stimulus-components library.
So when we click on the emoji symbol we expect the emoji-picker to be toggled. Let's create the `emoji_picker_controller.js` and add the library:
` yarn add emoji-mart`
`yarn add @emoji-mart/data` optional you can lazy load the data to optimize

When the controller connects:
  • We find the input part of the trix editor to be able to add the selected emojis in it
  • We create a Picker object
  • When the emoji is selected we insert the emoji where the cursor is.
  • That's it

import { Controller } from 'stimulus';
import data from '@emoji-mart/data'
import { Picker } from 'emoji-mart'

export default class extends Controller {
  static targets = ['pickerContainer']
  
  connect() {
    this.trixEditorElement = this.element.closest('trix-toolbar').nextElementSibling

    this.picker = new Picker({
      data: data,
      parent: this.pickerContainerTarget,
      onEmojiSelect: (emoji) => {        
        // We insert the emoji at the current cursor position
        const trixEditor = this.trixEditorElement.editor
        const currentPosition = trixEditor.getSelectedRange()[0]
        trixEditor.setSelectedRange([currentPosition, currentPosition])
        trixEditor.insertString(emoji.native)
      }
    })
  }
}










Feed
Sign up or Sign in to comment