# EmojiPicker

A search field, a row of category buttons and a scrolling grid of emoji, with a preview of the emoji under the pointer or the focus. Built in: 536 common emoji in eight categories, with English names to search. It has no frame: put it in a Popover, or use it inside MessageActions.

**Dependencies:** npm: 1 direct, 3 total; registry: 3 direct, 3 total.

## Usage

### When to use

- Pick an emoji to put in a message or as a reaction.
- Let someone search a set of emoji by name.

### When not to use

- Pick from a few fixed reactions. Use the quick reactions in MessageActions.
- Pick an icon for a project or a page. Use a grid of icon Buttons in a Popover.
- Rate something. Use Rating.

## Examples

### Picker

```tsx
<EmojiPicker onEmojiSelect={pickEmoji} className="rounded-container border border-border p-sm" />
```

### Frequently used

Emoji the user picks most come first, in their own section.

```tsx
<EmojiPicker frequent={["👍", "❤️", "😂", "🎉", "🙏", "🔥"]} onEmojiSelect={pickEmoji} className="rounded-container border border-border p-sm" />
```

### In a popover

The usual place: a button beside a field opens it.

```tsx
<Popover>
  <PopoverTrigger asChild>
    <Button variant="secondary" iconOnly aria-label="Add emoji">
      <IconMoodSmile size={16} />
    </Button>
  </PopoverTrigger>
  <PopoverContent className="w-auto p-sm">
    <EmojiPicker autoFocus onEmojiSelect={pickEmoji} />
  </PopoverContent>
</Popover>
```

## Do and don't

### Do

- Open it from a button in a Popover, and close the Popover when an emoji is picked.
- Pass frequent with the user's most used emoji, kept by your app.
- Pass categories with translated names when search should work in the page's language.

### Don't

- Do not use it to pick reactions only; MessageActions offers quick reactions first.
- Do not shrink it below 8 columns of md buttons on touch screens.
- Do not show emoji as images of text; keep the system emoji font.

## Props

| Name | Type | Values | Default | Description |
| --- | --- | --- | --- | --- |
| `onEmojiSelect` | `(emoji: string) => void` |  |  | Called with the emoji the user picks, such as 👍. |
| `frequent` | `string[]` |  |  | Emoji the user picks most, shown first. Keep the list yourself, such as in local storage. |
| `categories` | `{ id: string; label: string; emojis: { emoji: string; name: string; keywords?: string[] }[] }[]` |  |  | The categories to show. Default: the built-in set. The ids smileys, people, animals, food, activities, travel, objects and symbols pick a built-in icon. |
| `columns` | `number` |  | `8` | Emoji per row. |
| `showPreview` | `boolean` |  | `true` | Shows the emoji under the pointer or the focus, with its name, under the grid. |
| `autoFocus` | `boolean` |  | `false` | Focuses the search field on mount, such as when the picker opens in a Popover. |
| `labels` | `{ picker?: string; search?: string; searchPlaceholder?: string; categories?: string; frequent?: string; results?: string; empty?: string }` |  |  | Names and headings. Defaults: Emoji, Search emoji, Search, Emoji categories, Frequently used, Results, No emoji found. Vietnamese: Biểu tượng cảm xúc, Tìm biểu tượng cảm xúc, Tìm kiếm, Nhóm biểu tượng, Dùng thường xuyên, Kết quả, Không tìm thấy biểu tượng nào. |

## Anatomy

| Part | Description |
| --- | --- |
| `root` | The picker: search, categories, grid and preview, stacked, 288px wide. |
| `search` | An Input in size sm with a search icon. |
| `nav` | The row of category buttons, hidden while searching. |
| `category` | A 28px icon button that scrolls its section into view, with a 44px touch target. The section in view takes the muted accent fill. |
| `viewport` | The 256px scrolling area of sections. |
| `section` | One category: its heading over its grid. |
| `heading` | The category name above its emoji. |
| `item` | One emoji button, the size of an md control, at the xl text size. |
| `empty` | The text shown when nothing matches the search. |
| `preview` | The emoji under the pointer or the focus, with its name, under a line. |

## Accessibility

Role: `group`

| Keys | Action |
| --- | --- |
| `Arrow Down` | From the search field, moves into the grid. |
| `Arrow keys` | In the grid, move by one emoji or one row. Arrow Up from the first row goes back to the search field. |
| `Home / End` | In the grid, move to the first or the last emoji. |
| `Enter / Space` | Picks the focused emoji. Enter in the search field picks the first result. |
| `Tab` | Moves from the search field to the category buttons, then to the grid, which is one tab stop. |

- A group named by labels.picker (EN `Emoji`, VI `Biểu tượng cảm xúc`). The search field is named by labels.search.
- Each emoji is a button named by its name, such as EN `thumbs up`, so a screen reader never reads only the glyph.
- Each section is a region named by its heading. The category buttons are named by their category and the one in view has aria-current.
- The preview under the grid is drawn only; the buttons already say their names.
- When nothing matches, the empty text is a polite status, EN `No emoji found`.
- Built-in names are English. Pass categories with names in another language to search in it.

## Install

```bash
npx werewolf-ui add emoji-picker
```

Run `npx werewolf-ui init` once in your app before adding components. Init sets up tokens, their CSS import and agent rules. Add installs this component and its dependencies while preserving your theme. See [Installation](https://www.werewolf-ui.dev/docs/installation.md) for requirements and the alternative registry setup.
