Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Emoji Picker Dialog Block for React

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 React with Base 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 passed to DialogTrigger through render, 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.

  • Pro

    Reaction Picker Dialog

    Drawers and popovers

    A community chat with a reaction tray shown open under one message: six quick reactions, a More button that opens twelve more in one grid, arrow keys across it, and pills with counts on the message.

  • Pro

    Quick Reply Dialog

    Pickers and search

    A helpdesk ticket with its saved-replies dialog shown open: a searchable list of eight replies, a preview filled from the ticket, a flag and a field for each variable it cannot fill, an SMS character count and an Insert reply button that writes into the composer.

  • Pro

    Quick Note Dialog

    Notes and editing

    A sticky-note wall with its dialog shown open: a title, a note of up to 280 characters, an Idea, To-do, Reference or Later label, a reminder day on a calendar and a pin switch, and a new card that lands first on the wall.

  • Pro

    Feedback Rating Dialog

    Feedback and reports

    A help desk's ended chat with a one-tap satisfaction dialog shown open: five drawn faces from very bad to great that record the score at once, then an optional comment with a question that fits the score.

  • Pro

    Mood Check Dialog

    Feedback and reports

    A mood journal's home with a check-in dialog shown open: five faces from Rough to Great, tags for what is behind the mood, an optional note of 200 characters, and a week strip that fills in today's cell.

  • Pro

    Add Card Dialog

    Payments and plans

    A transit wallet's payment methods page with its add-card dialog shown open: a card drawn in greys that fills in as you type, a number that groups itself and names its network, checks on the number, expiry and code, and an Add card button that keeps only the last four digits.