EmojiPicker

Search and pick emojis with categories, skin tone selector, and virtualized grid

License

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 page for setup instructions.

😀Grinning Face
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:

😀Grinning Face
Size
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

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

Without search

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

😀Grinning Face
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:

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.

😀Grinning Face
Columns
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

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

Emoji size

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

😀Grinning Face
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:

😀Grinning Face

Current skin tone: 0

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.

😀Grinning Face
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:

😀Grinning Face
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:

😀Grinning Face
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:

😀Grinning Face
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:

😀Grinning Face
import data from '@emoji-mart/data';
import { emojiMartAdapter, EmojiPicker } from '@mantine/emoji';

const emojiData = emojiMartAdapter(data);

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

Controlled search

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

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.

<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.

KeyDescription
ArrowRightMoves focus to the next emoji
ArrowLeftMoves focus to the previous emoji
ArrowDownMoves focus one row down
ArrowUpMoves focus one row up
EnterSelects focused emoji
SpaceSelects focused emoji (grid only)
EscapeMoves focus from the grid back to the search input (only when the search input is displayed)
TabMoves focus between sections (search, category nav, grid, skin tone)
ArrowRightCategory nav: moves focus to the next category button, wraps around
ArrowLeftCategory nav: moves focus to the previous category button, wraps around
HomeCategory nav: moves focus to the first category button
EndCategory nav: moves focus to the last category button