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. |
open |
boolean | β | Reflected state attribute set by open()/close() methods. Not intended as initial markup. |
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
titlewith 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-emojito any container to replace shortcodes in text nodes on load. - Live input: Add
data-emojito 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.