An emoji picker panel for reactions, comments and messages, built to sit inline or inside a popover. A search field filters a built-in set of about 380 common emoji by name and keywords; category tabs with icons scroll the grid and follow along as it scrolls, with a marker that slides between them. A Recently used row is remembered in localStorage, a skin tone row applies one of the five modifiers to every emoji that takes it, and a preview bar names the hovered or focused emoji. The grid is fully keyboard driven, with arrows moving by row across sections, and each cell has a fixed size so the panel is exactly as wide as its columns.
The import and the props worth knowing about, in one place.
import { ReactionPicker } from "@/components/beste/component/reaction-picker";
<ReactionPicker onSelect={(emoji) => console.log("Picked", emoji)} />
// Inside a popover, focused on open, with a controlled skin tone
<ReactionPicker
autoFocus
skinTone={tone}
onSkinToneChange={(next) => console.log("Tone", next)}
onSelect={(emoji, entry) => console.log(emoji, entry.name)}
columns={9} // emoji per row
recent={false} // hide the Recently used row
tone="outline" // "muted" | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
/>Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Type in the field | Filter by name and keywords; Enter picks the first match and Escape clears the search. |
|---|---|
| Arrow down from the field | Move into the grid. |
| Arrow keys in the grid | Move between emoji; up and down keep the column across sections, and up from the top row returns to the field. |
| Home / End | Jump to the first or the last emoji. |
| Enter / Space | Pick the focused emoji. |
| Escape in the skin tone row | Close it and return to the tone button. |
Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
onSelect | (emoji: string, entry: EmojiEntry) => void | โ | Called with the emoji (skin tone applied) and its entry. |
skinTone | 0 | 1 | 2 | 3 | 4 | 5 | โ | Skin tone for emoji that take one. Pair with `onSkinToneChange` to control it. |
defaultSkinTone | 0 | 1 | 2 | 3 | 4 | 5 | โ | |
onSkinToneChange | (tone: SkinTone) => void | โ | |
recent | boolean | โ | Show the recently used row, remembered in localStorage. |
storageKey | string | โ | localStorage key for recent picks and the skin tone. |
maxRecent | number | โ | How many recent picks to keep. |
columns | number | โ | Emoji per row. |
placeholder | string | โ | |
autoFocus | boolean | โ | |
tone | "muted" | "outline" | "ghost" | โ | |
size | "sm" | "default" | "lg" | โ | |
className | string | โ | |
aria-label | string | โ | Accessible name for the panel. |