Emoji Picker
An emoji picker with autocomplete, virtualized scrolling, and arrow key navigation.
Example
EmojiPicker.css
Example
EmojiPicker.css
Example
EmojiPicker.css
import {Autocomplete, GridLayout, ListBox, ListBoxItem, Select, SelectValue, Size, useFilter, Virtualizer} from 'react-aria-components';
import {Button} from './Button';
import {Popover} from './Popover';
import {SearchField} from './SearchField';
import _emojis from 'emojibase-data/en/compact.json';
import './EmojiPicker.css';
const emojis = _emojis.filter((e) => !e.label.startsWith('regional indicator'));
export default function EmojiPicker() {
let {contains} = useFilter({ sensitivity: 'base' });
return (
<Select aria-label="Emoji" className="emoji-picker" defaultValue="🥳">
<Button variant="secondary">
<SelectValue />
</Button>
<Popover placement="bottom" className="emoji-picker-popover">
<Autocomplete filter={contains}>
<SearchField aria-label="Search" placeholder="Search emoji" autoFocus />
<Virtualizer
layout={GridLayout}
layoutOptions={{
minItemSize: new Size(32, 32),
maxItemSize: new Size(32, 32),
minSpace: new Size(4, 4),
preserveAspectRatio: true,
}}>
<ListBox className="emoji-list" items={emojis} aria-label="Emoji list" layout="grid">
{(item) => <EmojiItem id={item.unicode} item={item} />}
</ListBox>
</Virtualizer>
</Autocomplete>
</Popover>
</Select>
);
}
function EmojiItem({ id, item }: { id: string; item: (typeof emojis)[0] }) {
return (
<ListBoxItem
id={id}
value={item}
textValue={item.label + (item.tags || []).join(' ')}
className="emoji-item">
{item.unicode}
</ListBoxItem>
);
}