A lightweight, unstyled, and composable emoji picker for React.
If you are using shadcn/ui, you can also install it as a pre-built component via the shadcn CLI.
Learn more in the shadcn/ui section.
Import the EmojiPicker
parts and create your own component by composing them.
Apart from a few sizing and overflow defaults, the parts don’t have any styles out-of-the-box. Being composable, you can bring your own styles and apply them however you want: Tailwind CSS, CSS-in-JS, vanilla CSS via inline styles, classes, or by targeting the [frimousse-*]
attributes present on each part.
You might want to use it in a popover rather than on its own. Frimousse only provides the emoji picker itself so if you don’t have a popover component in your app yet, there are several libraries available: Radix UI, Base UI, Headless UI, and React Aria, to name a few.
If you are using shadcn/ui, you can install a pre-built version of the component which integrates with the existing shadcn/ui variables via the shadcn CLI.
It can be composed and combined with other shadcn/ui components like Popover.
Various styling-related details and examples.
The emoji picker doesn’t require hard-coded dimensions and instead supports dynamically adapting to the contents (e.g. the number of columns, the size of the rows, the padding within the sticky category headers, etc). One aspect to keep in mind is that inner components within EmojiPicker.List
should be of the same size (e.g. all rows should be of the same height) to prevent layout shifts.
The --frimousse-viewport-width
CSS variable can be used as a max-width
to prevent some areas from becoming wider than the automatically sized contents, when showing the hovered emoji’s name below for example.
And although not required, it’s still possible to force the emoji picker and its contents to be of a specific width, to fit the viewport on mobile for example.
Because of its virtualized nature, adding padding to EmojiPicker.List
can be tricky. We recommend adding horizontal padding to rows and category headers, and vertical padding on the list itself. Finally, to apply the same vertical padding to the viewport when keyboard navigating (which automatically scrolls to out-of-view rows), you can set the same value as scroll-margin-block
on rows.
Some emoji pickers like Slack’s display their emoji buttons with seemingly random background colors when active (either hovered or selected via keyboard navigation). This can be achieved by using :nth-child
selectors on rows and emojis to alternate through a list of colors. In the example below, a row’s first emoji has a red background, the second green, the third blue, then red again, and so on. All odd rows follow the same pattern, while even rows offset it by one to avoid every column using the same color, starting with blue instead of red.
Some other emoji pickers like Linear’s use the main color from the button’s emoji as background color instead. Extracting colors from emojis isn’t trivial, but a similar visual result can be achieved more easily by duplicating the emoji and scaling it to fill the background, then blurring it. In the example below, the blurred and duplicated emoji is built as a ::before
pseudo-element.
All parts and hooks, along their usage and options.
Surrounds all the emoji picker parts.
Options affecting the entire emoji picker are available on this component as props.
onEmojiSelect
(emoji: Emoji) => void
A callback invoked when an emoji is selected.
locale
Locale
Default is "en"The locale of the emoji picker.
skinTone
SkinTone
Default is "none"The skin tone of the emoji picker.
columns
number
Default is 10The number of columns in the list.
emojiVersion
number
Default is the most recent version supported by the current browserWhich Emoji version to use, to manually control which emojis are visible regardless of the current browser's supported Emoji versions.
All built-in div
props.
[frimousse-root]
Can be targeted in CSS for styling.
[data-focused]
Present when the emoji picker or its inner elements are focused.
--frimousse-emoji-font
<string>
A list of font families to use when rendering emojis.
--frimousse-viewport-width
<length>
The measured width of the viewport.
--frimousse-viewport-height
<length>
The measured height of the viewport.
--frimousse-row-height
<length>
The measured height of a row in the list.
--frimousse-category-header-height
<length>
The measured height of a category header in the list.
A search input to filter the list of emojis.
It can be controlled or uncontrolled.
All built-in input
props.
[frimousse-search]
Can be targeted in CSS for styling.
The scrolling container of the emoji picker.
All built-in div
props.
[frimousse-viewport]
Can be targeted in CSS for styling.
The list of emojis.
Inner components within the list can be customized via the components
prop.
components
Partial<EmojiPickerListComponents>
The inner components of the list.
All built-in div
props.
[frimousse-list]
Can be targeted in CSS for styling.
CategoryHeader
EmojiPickerListCategoryHeaderProps
The component used to render a sticky category header in the list.
All category headers should be of the same size.
[frimousse-category-header]
Can be targeted in CSS for styling.
category
Category
The category for this sticky header.
All built-in div
props.
Row
EmojiPickerListRowProps
The component used to render a row of emojis in the list.
All rows should be of the same size.
[frimousse-row]
Can be targeted in CSS for styling.
All built-in div
props.
Emoji
EmojiPickerListEmojiProps
The component used to render an emoji button in the list.
All emojis should be of the same size.
[frimousse-emoji]
Can be targeted in CSS for styling.
[data-active]
Present when the emoji is currently active (either hovered or selected via keyboard navigation).
emoji
Emoji & { isActive: boolean }
The emoji for this button, its label, and whether the emoji is currently active (either hovered or selected via keyboard navigation).
All built-in button
props.
Only renders when the emoji data is loading.
children
ReactNode
The content to render when the emoji data is loading.
All built-in span
props.
[frimousse-loading]
Can be targeted in CSS for styling.
Only renders when no emoji is found for the current search.
It can also expose the current search via a render callback to build a more detailed empty state.
children
ReactNode | ((props: EmojiPickerEmptyRenderProps) => ReactNode)
The content to render when no emoji is found for the current search, or a render callback which receives the current search value.
All built-in span
props.
[frimousse-empty]
Can be targeted in CSS for styling.
A button to change the current skin tone by cycling through the available skin tones.
The emoji used as visual can be customized.
If you want to build a custom skin tone selector, you can use the EmojiPicker.SkinTone
component or the useSkinTone
hook.
emoji
string
Default is "✋"The emoji to use as visual for the skin tone variations.
All built-in button
props.
[frimousse-skin-tone-selector]
Can be targeted in CSS for styling.
Exposes the current skin tone and a function to change it via a render callback.
It can be used to build a custom skin tone selector: pass an emoji you want to use as visual and it will return its skin tone variations.
If you prefer to use a hook rather than a component, useSkinTone
is also available.
An already-built skin tone selector is also available, EmojiPicker.SkinToneSelector
.
emoji
string
Default is "✋"The emoji to use as visual for the skin tone variations.
Exposes the currently active emoji (either hovered or selected via keyboard navigation) via a render callback.
It can be used to build a preview area next to the list.
If you prefer to use a hook rather than a component, useActiveEmoji
is also available.
Returns the current skin tone and a function to change it.
It can be used to build a custom skin tone selector: pass an emoji you want to use as visual and it will return its skin tone variations.
If you prefer to use a component rather than a hook, EmojiPicker.SkinTone
is also available.
An already-built skin tone selector is also available, EmojiPicker.SkinToneSelector
.
emoji
string
Default is "✋"The emoji to use as visual for the skin tone variations.
Returns the currently active emoji (either hovered or selected via keyboard navigation).
It can be used to build a preview area next to the list.
If you prefer to use a component rather than a hook, EmojiPicker.ActiveEmoji
is also available.
The name “frimousse” means “little face” in French, and it can also refer to smileys and emoticons.
The emoji picker component was originally created for the Liveblocks Comments default components, within @liveblocks/react-ui
.
The emoji data is based on Emojibase.