Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Emoji Picker Dialog Block for Svelte

A team chat's page with its emoji picker shown open: a frequently used row, a search over 96 emoji, a skin tone select, six category tabs with an arrow-key grid, and a foot line that names the emoji in focus, adding each one to the message box behind it.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Let people add emoji to a message without leaving the keyboard, with this emoji picker for Svelte with Ark UI. It opens from the Team chat page of Chatloom: the header holds an outline Button, and a thread of messages with its message box is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The dialog shows the message so far, a row of the six emoji used most that picking reorders, a search Input, a skin tone Select for hands and people, and six category Tabs of 16 emoji each in an eight-column grid you walk with the arrow keys. A foot line names the emoji in focus. Pressing one adds it to the message and keeps the picker open; Done, the only Shine Button, or Escape closes it. For preview the picker is drawn open in place when the page loads, above the message box; the header button opens the real Dialog, with the same state. For chat, comments, notes and any app with a text box.

FAQ

Why is the dialog already open, and what do I keep?

So you can see it without a click. On load the picker is a copy drawn in place over the page: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The header's Add emoji button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same PickerFields component and share the block's state, so what you set in the copy is there in the real one. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.

Why does an emoji block use emoji when the others avoid them?

Because here the glyphs are the content, not decoration. They are typed as data, each with a spoken name and a few search words, and the buttons carry the name as their accessible label while the glyph itself is hidden from assistive technology. Everything around them is icons and theme tokens. Emoji look different on every platform, so the grid sizes its cells for the glyph rather than drawing them.

How do skin tones work?

The Select offers Default, Light, Medium and Dark. Hands and people in the data are flagged, and for those the glyph is its base character without the variation selector plus one Fitzpatrick modifier, so the grid and the message both show the toned version. Emoji without a tone, like the eyes or a heart, ignore the Select. In your app keep the tone with the user's preferences.

What stays local, and how do I wire it for real?

Everything. Each pick adds the glyph to the message text in local state, moves the emoji to the front of Frequently used and is spoken in a polite status message; nothing is sent. In your app insert at the caret of your real message field in onPick, store the frequent list per user, and expand CATEGORIES from a complete emoji dataset. The search covers names and keywords, so a longer list needs an index, not a filter on every key.

Is it accessible from the keyboard?

Yes. The real dialog is named by its title and described by its sentence, focus is trapped while it is open, and Escape and Done return focus to the Add emoji button. The trigger is the button wrapped in DialogTrigger with asChild, and the dialog is controlled with open and onOpenChange. The copy shown on load moves no focus; Escape inside it and its close button close it and put focus back on the Add emoji button. Inside a grid the arrow keys walk the emoji (left and right swap in a right-to-left page), Home and End jump to the ends, there is one tab stop per grid, and Enter or Space adds the focused emoji and says its name.

How does it look on a phone?

The copy shown on load docks to the foot of the page as a bottom sheet with Done pinned at the bottom; on larger screens it sits at the bottom start, above the message box. The grid stays eight columns wide with cells sized for a thumb, and the search and tone share one row. The real dialog keeps the Dialog's own phone layout: a sheet stuck to the bottom of the screen.