emoji-picker

Accessible emoji picker with search, category tabs, and target insertion. Browse, search, or select emoji and insert directly into inputs, textareas, or contenteditable elements.

Overview

The <emoji-picker> component provides an accessible popup for browsing, searching, and selecting emoji. It can insert directly into a target input, textarea, or contenteditable element, or dispatch events for custom handling.

<textarea id="msg" rows="3"></textarea> <emoji-picker for="msg"> <button data-trigger type="button">😀</button> </emoji-picker>

Attributes

Attribute Type Default Description
for string ID of target input, textarea, or contenteditable element for insertion.
data-open boolean Reflected attribute indicating open state.
recent-limit number 24 Maximum number of recently used emoji to store.

Events

Event Detail Description
emoji-picker:select { shortcode, emoji, name, keywords } Fired when an emoji is selected.
emoji-picker:open Fired when the picker panel opens.
emoji-picker:close Fired when the picker panel closes.
const picker = document.querySelector('emoji-picker'); picker.addEventListener('emoji-picker:select', (e) => { console.log(e.detail.emoji); // "🚀" console.log(e.detail.shortcode); // "rocket" console.log(e.detail.name); // "Rocket" });

Custom Trigger

Provide your own trigger button as a child element with data-trigger. If no trigger is found, one is auto-created.

<emoji-picker for="comment"> <button data-trigger type="button" aria-label="Add emoji"> Add Emoji </button> </emoji-picker>

Without Target

Omit the for attribute to use the picker without auto-insertion. Listen for the emoji-picker:select event and handle insertion yourself.

<!-- No "for" attribute — handle insertion yourself --> <emoji-picker> <button data-trigger type="button">😀</button> </emoji-picker> <script> document.querySelector('emoji-picker') .addEventListener('emoji-picker:select', (e) => { // Insert wherever you want myEditor.insert(e.detail.emoji); }); </script>

Keyboard Navigation

Key Context Action
Enter / Space Trigger Toggle picker open/close
Escape Any Close picker, return focus to trigger
Arrow Down Search input Move focus to first emoji in grid
Arrow Up Grid (first row) Return focus to search input
Arrow keys Grid Navigate between emoji (8-column grid)
Home / End Grid Jump to first/last emoji
Enter / Space Grid Select focused emoji
Tab Grid Close picker

Recents

Selected emoji are stored in localStorage (key: vb-emoji-recent) and shown as a “Recently Used” section at the top of the grid. The recent-limit attribute controls how many are kept.

Progressive Enhancement

Without JavaScript, the trigger button remains visible but non-functional. The picker panel is hidden by default. Users can still type emoji directly using their OS emoji keyboard (Cmd+Ctrl+Space on macOS, Win+. on Windows).

Accessibility

  • The picker panel uses role="dialog" with a descriptive label.
  • Category tabs use role="tablist" / role="tab".
  • The emoji grid uses role="grid" / role="gridcell".
  • Full keyboard navigation with arrow keys, Home/End, and Escape.
  • Focus is managed: search input on open, trigger on close.
  • Each emoji button has a title with the emoji name and shortcode.

Related: data-emoji Attribute

The data-emoji attribute provides a complementary approach — replacing :shortcode: text patterns with emoji characters:

  • Static content: Add data-emoji to any container to replace shortcodes in text nodes on load.
  • Live input: Add data-emoji to a <textarea> or <input> for live replacement as the user types.

Use emoji-picker when users need to browse and discover emoji. Use data-emoji when users already know the shortcode they want to type.