Marble UI
← Components

Emoji Picker

Preview: Popover

Emoji grid with search and category headings; arrow keys move through the grid (GridList), Enter picks. `autoFocus` focuses the search (on in the popover picker).

Import

import { EmojiGrid, EmojiPicker } from '@marbleui/ui'

Props

<EmojiGrid>

PropTypeDefaultDescription
onSelect *required(emoji: string) => void—
autoFocusboolean—
classNamestring—
emojis[string, string, string][]defaultEmojis

<EmojiPicker>

Button that opens the emoji grid in a popover.

PropTypeDefaultDescription
onSelect *required(emoji: string) => void—
childrenReactNode—
labelstring'Add emoji'

Accessibility

Keyboard interaction, focus management and ARIA semantics come from the underlying primitives: React Aria Button · React Aria Collection · React Aria Dialog · React Aria DialogTrigger · React Aria GridList · React Aria GridListHeader · React Aria GridListItem · React Aria GridListSection · React Aria Input · React Aria SearchField. Follow the primitive's docs for the full keyboard map.

Usage notes

Emoji choice for reactions and message composers. EmojiPicker is a button that opens EmojiGrid in a popover; render EmojiGrid directly to embed it in your own panel.

<EmojiPicker label="Add reaction" onSelect={(emoji) => addReaction(messageId, emoji)} />
<EmojiGrid emojis={workspaceEmojis} onSelect={insertEmoji} />
  • The built-in set is small (62 emoji, no skin tones or recents). Pass your own emojis as [emoji, name, category] tuples with lowercase names; search matches the name, case-insensitively. Emoji are grouped under category headings in the order categories first appear.
  • In EmojiPicker the search box takes focus when the popover opens; an inline EmojiGrid only does with autoFocus. Tab moves into the grid, arrow keys move between emoji, Enter picks; each emoji is announced by its name.
  • EmojiPicker closes after a pick. children replaces the default 🙂 trigger, and label (default “Add emoji”) is the trigger’s accessible name.
Example source · show
import { useState } from 'react'
import { EmojiGrid, EmojiPicker } from './emoji-picker'

function InPopover() {
  const [text, setText] = useState('Ship it ')
  return <div className="flex w-80 items-center gap-1 rounded-lg border border-border bg-surface px-2"><span className="flex-1 truncate py-2 text-sm text-fg">{text}</span><EmojiPicker onSelect={(e) => setText((t) => t + e)} /></div>
}
function Inline() {
  const [last, setLast] = useState('')
  return <div className="flex flex-col gap-2 rounded-xl border border-border bg-surface p-3"><EmojiGrid onSelect={setLast} /><span aria-live="polite" className="text-sm text-fg-muted">Picked: {last || '—'}</span></div>
}
export const styles = { Popover: InPopover, Inline }

Source: packages/ui/src/emoji-picker/emoji-picker.tsx

Catalog

Category
inputs
Priority
Extra
Primitive
composed
React Aria
GridList + SearchField