# EmojiPicker
Package: @mantine/emoji
Import: import { EmojiPicker } from '@mantine/emoji';
Description: Search and pick emojis with categories, skin tone selector, and virtualized grid

## Usage

`EmojiPicker` displays a searchable emoji grid with category navigation, skin tone selector,
and emoji preview. Emoji data is passed with the `data` prop, see the
[Getting started](https://mantine.dev/llms/emoji-getting-started.md) page for setup instructions.

```tsx
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  return (
    <EmojiPicker
      data={emojiData}
      onEmojiSelect={(emoji) => console.log(emoji)}
    />
  );
}
```


## Size

Use the `size` prop to change the size of all inner elements:

```tsx
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  return <EmojiPicker data={emojiData} size="sm" />;
}
```


## Without search

Set `withSearch={false}` to hide the search input:

```tsx
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  return <EmojiPicker data={emojiData} withSearch={false} />;
}
```


## Without preview

Set `withPreview={false}` and `withSkinToneSelector={false}` to hide the footer area:

```tsx
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  return (
    <EmojiPicker
      data={emojiData}
      withPreview={false}
      withSkinToneSelector={false}
    />
  );
}
```


## Custom columns

Use the `columns` prop to change the number of emojis per row. The picker width
adjusts automatically based on the number of columns and emoji size.

```tsx
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  return <EmojiPicker data={emojiData} columns={9} />;
}
```


## Emoji size

Use the `emojiSize` prop to change the size of emoji buttons. Emoji font size is derived from
this value.

```tsx
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  return <EmojiPicker data={emojiData} emojiSize={48} columns={7} />;
}
```


## Skin tone

The skin tone selector is displayed in the preview area. Click it to open a popover
with all skin tone options. Use `skinTone` and `onSkinToneChange` props to control the value:

```tsx
import { useState } from 'react';
import { Text } from '@mantine/core';
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  const [skinTone, setSkinTone] = useState(0);

  return (
    <>
      <EmojiPicker
        data={emojiData}
        skinTone={skinTone}
        onSkinToneChange={setSkinTone}
      />
      <Text mt="md">Current skin tone: {skinTone}</Text>
    </>
  );
}
```


## Scroll area

Use the `scrollAreaProps` prop to pass props to the internal `ScrollArea`, for example
to change its height. The default height is 300px.

```tsx
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  return (
    <EmojiPicker
      data={emojiData}
      scrollAreaProps={{ style: { height: 500 }, type: 'always' }}
    />
  );
}
```


## Category labels and localization

Override category labels with the `categoryLabels` prop (keyed by canonical category ID),
and UI strings with the `labels` prop:

```tsx
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  return (
    <EmojiPicker
      data={emojiData}
      categoryLabels={{
        people: 'Лица и люди',
        nature: 'Животные и природа',
        foods: 'Еда и напитки',
        activity: 'Активность',
        places: 'Путешествия',
        objects: 'Объекты',
        symbols: 'Символы',
        flags: 'Флаги',
      }}
      labels={{
        search: 'Поиск',
        noResults: 'Ничего не найдено',
        searchResults: 'Результаты поиска',
      }}
    />
  );
}
```


## Search icon

Customize the search input with the `searchInputProps` prop. For example, you can add a
search icon to the left section:

```tsx
import { MagnifyingGlassIcon } from '@phosphor-icons/react';
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  return (
    <EmojiPicker
      data={emojiData}
      searchInputProps={{ leftSection: <MagnifyingGlassIcon /> }}
    />
  );
}
```


## Empty search content

Customize the content shown when search yields no results with the `emptySearchContent` prop:

```tsx
import { useState } from 'react';
import { MagnifyingGlassIcon } from '@phosphor-icons/react';
import { Button, Center, Stack, Text } from '@mantine/core';
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  const [search, setSearch] = useState('');

  return (
    <EmojiPicker
      data={emojiData}
      searchValue={search}
      onSearchChange={setSearch}
      emptySearchContent={
        <Center h="100%">
          <Stack align="center" gap="xs">
            <MagnifyingGlassIcon size={32} />
            <Text size="sm" c="dimmed" ta="center">
              No emojis match your search
            </Text>
            <Button variant="light" size="compact-sm" onClick={() => setSearch('')}>
              Clear search
            </Button>
          </Stack>
        </Center>
      }
    />
  );
}
```


## Toggle sections

Use these boolean props to toggle individual sections:

```tsx
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

function Demo() {
  return <EmojiPicker data={emojiData} withSearch={true} withCategoryNav={true} withPreview={true} withSkinToneSelector={true} />;
}
```


## Controlled search

Use `searchValue` and `onSearchChange` props to control the search input value:

```tsx
import { useState } from 'react';
import { EmojiPicker } from '@mantine/emoji';
import { emojiData } from './emoji-data';

function Demo() {
  const [search, setSearch] = useState('');

  return (
    <EmojiPicker
      data={emojiData}
      searchValue={search}
      onSearchChange={setSearch}
    />
  );
}
```

## Unsupported emoji detection

Set `withUnsupportedDetection` to hide emojis that are not supported by the current browser
or operating system. To detect support, each emoji is drawn on a canvas.

```tsx
<EmojiPicker data={emojiData} withUnsupportedDetection />
```

This feature is disabled by default because canvas-based detection has edge cases across platforms.

## Keyboard navigation

The category navigation and the emoji grid are single tab stops. `ArrowDown`, `ArrowUp` and `Enter` keys also work
when the search input is focused: `Enter` selects the first search result.


#### Props

**EmojiPicker props**

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| autoFocus | boolean | - | Determines whether the search input is focused on mount |
| categoryLabels | Record<string, string> | - | Override category labels by category id |
| columns | number | - | Number of emoji columns |
| data | EmojiPickerData | required | Emoji data object, use `emojiMartAdapter` or `emojibaseAdapter` to convert data |
| defaultSkinTone | number | - | Default skin tone value for uncontrolled state |
| emojiSize | number | - | Custom emoji button size in px, overrides size-based value |
| emptySearchContent | React.ReactNode | - | Content displayed when search yields no results |
| labels | EmojiPickerLabels | - | Override UI labels (search placeholder, no results text, etc.) |
| onEmojiSelect | (emoji: EmojiPickerEmoji) => void | - | Called when an emoji is selected |
| onSearchChange | (value: string) => void | - | Called when search value changes |
| onSkinToneChange | (skinTone: number) => void | - | Called when skin tone changes |
| scrollAreaProps | ScrollAreaProps | - | Props passed to the internal `ScrollArea` component |
| searchInputProps | InputProps | - | Props passed to the search `Input` component |
| searchPlaceholder | string | - | Search input placeholder |
| searchValue | string | - | Controlled search input value |
| size | MantineSize | - | Controls size of all inner elements |
| skinTone | number | - | Controlled skin tone value (0–5) |
| withCategoryNav | boolean | - | Determines whether the category navigation bar is displayed |
| withPreview | boolean | - | Determines whether the emoji preview area is displayed |
| withSearch | boolean | - | Determines whether the search input is displayed |
| withSkinToneSelector | boolean | - | Determines whether the skin tone selector is displayed |
| withUnsupportedDetection | boolean | - | Determines whether unsupported emojis are filtered out |

**EmojiPicker.Input props**

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| clearButtonProps | InputClearButtonProps | - | Props passed down to the clear button |
| clearable | boolean | - | Determines whether the clear button is displayed |
| closeOnSelect | boolean | - | Determines whether the popover closes after emoji is selected |
| data | EmojiPickerData | required | Emoji data object, use `emojiMartAdapter` or `emojibaseAdapter` to convert data |
| defaultOpened | boolean | - | Default popover opened state for uncontrolled mode |
| defaultValue | string \| null | - | Default emoji id value for uncontrolled state |
| description | React.ReactNode | - | Contents of `Input.Description` component. If not set, description is not displayed. |
| descriptionProps | InputDescriptionProps & DataAttributes & PlaceholderPolymorphicProps | - | Props passed down to the `Input.Description` component |
| disabled | boolean | - | Determines whether the input is disabled |
| error | React.ReactNode | - | Contents of `Input.Error` component. If not set, error is not displayed. |
| errorProps | InputErrorProps & DataAttributes & PlaceholderPolymorphicProps | - | Props passed down to the `Input.Error` component |
| inputContainer | (children: ReactNode) => ReactNode | - | Render function to wrap the input element. Useful for adding tooltips, popovers, or other wrappers around the input. |
| inputSize | string | - | HTML `size` attribute for the input element (number of visible characters) |
| inputWrapperOrder | ("input" \| "label" \| "description" \| "error")[] | - | Controls order and visibility of wrapper elements. Only elements included in this array will be rendered. |
| label | React.ReactNode | - | Contents of `Input.Label` component. If not set, label is not displayed. |
| labelProps | InputLabelProps & DataAttributes & PlaceholderPolymorphicProps | - | Props passed down to the `Input.Label` component |
| leftSection | React.ReactNode | - | Content section displayed on the left side of the input |
| leftSectionPointerEvents | React.CSSProperties["pointerEvents"] | - | Sets `pointer-events` styles on the `leftSection` element. Use `'all'` when section contains interactive elements (buttons, links). |
| leftSectionProps | React.ComponentProps<"div"> | - | Props passed down to the `leftSection` element |
| leftSectionWidth | React.CSSProperties["width"] | - | Left section width, used to set `width` of the section and input `padding-left`, by default equals to the input height |
| loaderProps | LoaderProps | - | Props passed down to the `Loader` component displayed when `loading` prop is set |
| loading | boolean | - | Displays loading indicator in the left or right section |
| loadingPosition | "left" \| "right" | - | Position of the loading indicator |
| onChange | (value: string \| null) => void | - | Called when value changes |
| onEmojiSelect | (emoji: EmojiPickerEmoji) => void | - | Called when an emoji is selected |
| onOpenedChange | (opened: boolean) => void | - | Called when popover opened state changes |
| opened | boolean | - | Controlled popover opened state |
| pickerProps | Omit<EmojiPickerProps, "data" \| "onEmojiSelect"> | - | Props passed to the `EmojiPicker` component inside the dropdown |
| placeholder | string | - | Input placeholder displayed when no emoji is selected |
| pointer | boolean | - | Determines whether the input should have `cursor: pointer` style. Use when input acts as a button-like trigger (e.g., `component="button"` for Select/DatePicker). |
| popoverProps | Omit<PopoverProps, "onChange" \| "children" \| "opened" \| "defaultOpened"> | - | Props passed to the `Popover` component, use `opened`, `defaultOpened` and `onOpenedChange` props to control opened state |
| radius | MantineRadius \| number | - | Key of `theme.radius` or any valid CSS value to set `border-radius`, numbers are converted to rem |
| readOnly | boolean | - | Determines whether the input is in read-only mode |
| required | boolean | - | Adds required attribute to the input and a red asterisk on the right side of label |
| rightSection | React.ReactNode | - | Content section displayed on the right side of the input |
| rightSectionPointerEvents | React.CSSProperties["pointerEvents"] | - | Sets `pointer-events` styles on the `rightSection` element. Use `'all'` when section contains interactive elements (buttons, links). |
| rightSectionProps | React.ComponentProps<"div"> | - | Props passed down to the `rightSection` element |
| rightSectionWidth | React.CSSProperties["width"] | - | Right section width, used to set `width` of the section and input `padding-right`, by default equals to the input height |
| size | MantineSize | - | Controls input `height`, horizontal `padding`, and `font-size` |
| success | React.ReactNode | - | Contents of `Input.Success` component. If not set, success is not displayed. |
| successProps | InputSuccessProps & DataAttributes & PlaceholderPolymorphicProps | - | Props passed down to the `Input.Success` component |
| value | string \| null | - | Controlled emoji id value |
| withAsterisk | boolean | - | If set, the required asterisk is displayed next to the label. Overrides `required` prop. Does not add required attribute to the input. |
| withErrorStyles | boolean | - | Determines whether the input should have red border and red text color when the `error` prop is set |
| withSuccessStyles | boolean | - | Determines whether the input should have green border when the `success` prop is set |
| wrapperProps | WrapperProps | - | Props passed down to the root element |

**EmojiPicker.Popover props**

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| autoFocus | boolean | - | Determines whether the search input is focused on mount |
| categoryLabels | Record<string, string> | - | Override category labels by category id |
| children | React.ReactNode | required | Popover target element |
| closeOnSelect | boolean | - | Determines whether the popover closes after emoji is selected |
| columns | number | - | Number of emoji columns |
| data | EmojiPickerData | required | Emoji data object, use `emojiMartAdapter` or `emojibaseAdapter` to convert data |
| defaultOpened | boolean | - | Default popover opened state for uncontrolled mode |
| defaultSkinTone | number | - | Default skin tone value for uncontrolled state |
| emojiSize | number | - | Custom emoji button size in px, overrides size-based value |
| emptySearchContent | React.ReactNode | - | Content displayed when search yields no results |
| labels | EmojiPickerLabels | - | Override UI labels (search placeholder, no results text, etc.) |
| onEmojiSelect | (emoji: EmojiPickerEmoji) => void | - | Called when an emoji is selected |
| onOpenedChange | (opened: boolean) => void | - | Called when popover opened state changes |
| onSearchChange | (value: string) => void | - | Called when search value changes |
| onSkinToneChange | (skinTone: number) => void | - | Called when skin tone changes |
| opened | boolean | - | Controlled popover opened state |
| popoverProps | Omit<PopoverProps, "onChange" \| "children" \| "opened" \| "defaultOpened"> | - | Props passed to the `Popover` component, use `opened`, `defaultOpened` and `onOpenedChange` props to control opened state |
| scrollAreaProps | ScrollAreaProps | - | Props passed to the internal `ScrollArea` component |
| searchInputProps | InputProps | - | Props passed to the search `Input` component |
| searchPlaceholder | string | - | Search input placeholder |
| searchValue | string | - | Controlled search input value |
| size | MantineSize | - | Controls size of all inner elements |
| skinTone | number | - | Controlled skin tone value (0–5) |
| withCategoryNav | boolean | - | Determines whether the category navigation bar is displayed |
| withPreview | boolean | - | Determines whether the emoji preview area is displayed |
| withSearch | boolean | - | Determines whether the search input is displayed |
| withSkinToneSelector | boolean | - | Determines whether the skin tone selector is displayed |
| withUnsupportedDetection | boolean | - | Determines whether unsupported emojis are filtered out |


#### Styles API

EmojiPicker component supports Styles API. With Styles API, you can customize styles of any inner element. Follow the documentation to learn how to use CSS modules, CSS variables and inline styles to get full control over component styles.

**EmojiPicker selectors**

| Selector | Static selector | Description |
|----------|----------------|-------------|
| root | .mantine-EmojiPicker-root | Root element |
| search | .mantine-EmojiPicker-search | Search input wrapper |
| searchInput | .mantine-EmojiPicker-searchInput | Search text input |
| categoryNav | .mantine-EmojiPicker-categoryNav | Category navigation bar |
| categoryNavButton | .mantine-EmojiPicker-categoryNavButton | Category navigation button |
| content | .mantine-EmojiPicker-content | Scrollable emoji grid area |
| empty | .mantine-EmojiPicker-empty | Content displayed when search yields no results |
| categoryLabel | .mantine-EmojiPicker-categoryLabel | Category label row |
| grid | .mantine-EmojiPicker-grid | Row of emoji buttons |
| emoji | .mantine-EmojiPicker-emoji | Individual emoji button |
| preview | .mantine-EmojiPicker-preview | Footer preview area |
| previewEmoji | .mantine-EmojiPicker-previewEmoji | Emoji displayed in preview |
| previewName | .mantine-EmojiPicker-previewName | Emoji name displayed in preview |
| skinToneDropdown | .mantine-EmojiPicker-skinToneDropdown | Skin tone popover dropdown |
| skinToneSelector | .mantine-EmojiPicker-skinToneSelector | Skin tone selector wrapper |
| skinToneButton | .mantine-EmojiPicker-skinToneButton | Individual skin tone button |

**EmojiPicker CSS variables**

| Selector | Variable | Description |
|----------|----------|-------------|
| root | --ep-columns | Number of columns in the emoji grid |
| root | --ep-emoji-size | Controls `width` and `height` of emoji buttons |
| root | --ep-emoji-fz | Controls `font-size` of emoji characters |
| root | --ep-preview-py | Controls vertical `padding` of the preview area |
| root | --ep-skin-tone-size | Controls `width` and `height` of skin tone buttons |
| root | --ep-skin-tone-fz | Controls `font-size` of skin tone characters |

**EmojiPicker data attributes**

| Selector | Attribute | Condition | Value |
|----------|-----------|-----------|-------|
| emoji | data-focused | Emoji is active during keyboard navigation | - |
| skinToneButton | data-active | Skin tone button is currently selected | - |

**EmojiPickerinput selectors**

| Selector | Static selector | Description |
|----------|----------------|-------------|
| wrapper | .mantine-EmojiPickerinput-wrapper | Root element of the Input |
| input | .mantine-EmojiPickerinput-input | Input element |
| section | .mantine-EmojiPickerinput-section | Left and right sections |
| bottomSection | .mantine-EmojiPickerinput-bottomSection | Bottom section element, rendered inside the input border at the bottom |
| root | .mantine-EmojiPickerinput-root | Root element |
| label | .mantine-EmojiPickerinput-label | Label element |
| required | .mantine-EmojiPickerinput-required | Required asterisk element, rendered inside label |
| description | .mantine-EmojiPickerinput-description | Description element |
| error | .mantine-EmojiPickerinput-error | Error element |
| success | .mantine-EmojiPickerinput-success | Success element |
| dropdown | .mantine-EmojiPickerinput-dropdown | Popover dropdown |
| inputValue | .mantine-EmojiPickerinput-inputValue | Wrapper of the selected emoji and its name |
| inputEmoji | .mantine-EmojiPickerinput-inputEmoji | Selected emoji character displayed in the input |
| inputEmojiName | .mantine-EmojiPickerinput-inputEmojiName | Selected emoji name displayed next to the emoji |
