- Uses IndexedDB, so it consumes [far less memory](https://nolanlawson.com/2020/06/28/introducing-emoji-picker-element-a-memory-efficient-emoji-picker-for-the-web/) than other emoji pickers
- [Button with tooltip/popover](https://nolanlawson.github.io/emoji-picker-element/demos/tooltip/index.html) ([source](https://github.com/nolanlawson/emoji-picker-element/blob/master/docs/demos/tooltip/index.html))
- [Inserting emoji into a text input](https://nolanlawson.github.io/emoji-picker-element/demos/input/index.html) ([source](https://github.com/nolanlawson/emoji-picker-element/blob/master/docs/demos/input/index.html))
- [In a React app](https://nolanlawson.github.io/emoji-picker-element/demos/react/index.html) ([source](https://github.com/nolanlawson/emoji-picker-element/blob/master/docs/demos/react/index.html))
- [Fallback for missing flag emoji on Windows](https://nolanlawson.github.io/emoji-picker-element/demos/flags/index.html) ([source](https://github.com/nolanlawson/emoji-picker-element/blob/master/docs/demos/flags/index.html))
[Emoji support varies](https://nolanlawson.com/2022/04/08/the-struggle-of-using-native-emoji-on-the-web/) across browsers and operating systems. By default, `emoji-picker-element` will hide unsupported emoji from the picker.
To work around this, you can use [a custom emoji font](#custom-emoji-font) or [polyfill flag emoji on Windows](#polyfilling-flag-emoji-on-windows).
#### Custom emoji font
To use a custom emoji font, first set the `--emoji-font-family` CSS property:
```css
emoji-picker {
--emoji-font-family: MyCustomFont;
}
```
Then, specify the maximum emoji version supported by the font (see [Emojipedia](https://emojipedia.org/emoji-versions/) for a list of versions).
If the `emoji-version`/`emojiVersion` option is set, then `emoji-picker-element` will not attempt to detect unsupported emoji or hide them.
Also note that support for color fonts [varies across browsers and OSes](https://caniuse.com/colr), and some browsers may have <ahref="https://github.com/nolanlawson/emoji-picker-element/pull/308#issuecomment-1367491149">bugs</a> or not render the font at all. Be careful to test your supported browsers when using this approach.
#### Polyfilling flag emoji on Windows
As of this writing, [Windows does not support country flag emoji](https://answers.microsoft.com/en-us/windows/forum/all/where-are-the-flag-emoji-in-windows-10/93daa6e8-880a-48b1-9891-ab5bfbfbce98). This is only a problem in Chromium-based browsers, because Firefox ships with its own emoji font.
To work around this, you can use [country-flag-emoji-polyfill](https://www.npmjs.com/package/country-flag-emoji-polyfill):
```js
import { polyfillCountryFlagEmojis } from 'country-flag-emoji-polyfill';
// emoji-picker-element will use "Twemoji Mozilla" and fall back to other fonts for non-flag emoji
polyfillCountryFlagEmojis('Twemoji Mozilla');
```
Note that you do not need to do this if you are using [a custom emoji font](#custom-emoji-font).
`emoji-picker-element` uses [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM), so its inner styling cannot be (easily) changed with arbitrary CSS. Refer to the API below for style customization.
| `--background` | `#fff` | `#222` | Background of the entire `<emoji-picker>` |
| `--border-color` | `#e0e0e0` | `#444` | |
| `--border-size` | `1px` | | Width of border used in most of the picker |
| `--button-active-background` | `#e6e6e6` | `#555555` | Background of an active button |
| `--button-hover-background` | `#d9d9d9` | `#484848` | Background of a hovered button |
| `--category-emoji-padding` | `var(--emoji-padding)` | | Vertical/horizontal padding on category emoji, if you want it to be different from `--emoji-padding` |
| `--category-emoji-size` | `var(--emoji-size)` | | Width/height of category emoji, if you want it to be different from `--emoji-size` |
| `--category-font-color` | `#111` | `#efefef` | Font color of custom emoji category headings |
| `--category-font-size` | `1rem` | | Font size of custom emoji category headings |
| `--emoji-font-family` | `"Twemoji Mozilla","Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji","EmojiOne Color","Android Emoji",sans-serif` | | Font family for a custom emoji font (as opposed to native emoji) |
| `--emoji-padding` | `0.5rem` | | Vertical and horizontal padding on emoji |
| `--emoji-size` | `1.375rem` | | Width and height of all emoji |
| `--indicator-color` | `#385ac1` | `#5373ec` | Color of the nav indicator |
| `--indicator-height` | `3px` | | Height of the nav indicator |
For accessibility reasons, `emoji-picker-element` displays a prominent focus ring for keyboard users. This uses [`:focus-visible`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible) under the hood. To properly support [browsers that do not support `:focus-visible`](https://caniuse.com/css-focus-visible), you can use the [focus-visible](https://github.com/WICG/focus-visible) polyfill, e.g.:
For small screen sizes, you should probably add some CSS like the following:
```css
@media screen and (max-width: 320px) {
emoji-picker {
--num-columns: 6;
--category-emoji-size: 1.125rem;
}
}
```
`emoji-picker-element` does not ship with any CSS to explicitly handle small screen sizes. The right CSS depends on which screen sizes your app supports, and the size of the picker within your app. Perhaps in the future [container queries](https://caniuse.com/css-container-queries) can solve this problem.
| `dataSource` | string | "https://cdn.jsdelivr.net/npm/emoji-picker-element-data@^1/en/emojibase/data.json" | URL to fetch the emoji data from (`data-source` when used as an attribute) |
| `emojiVersion` | number | - | Maximum supported emoji version as a number (e.g. `14.0` or `13.1`). Setting this disables the default emoji support detection. |
| `i18n` | I18n | - | i18n object (see below for details) |
| `locale` | string | "en" | Locale string |
| `skinToneEmoji` | string | "🖐️" | The emoji to use for the skin tone picker (`skin-tone-emoji` when used as an attribute) |
Community-provided translations for some languages [are available](https://github.com/nolanlawson/emoji-picker-element/tree/master/src/picker/i18n). You can use them like so:
Note that translations for the interface (`i18n`) are not the same as translations for the emoji data (`dataSource` and `locale`). To support both, you should do something like:
If a built-in translation for your target language is not available, you can also write your own translation and pass it in as `i18n`. Please feel free to contribute your translation [here](https://github.com/nolanlawson/emoji-picker-element/tree/master/src/picker/i18n).
Note that under the hood, IndexedDB data is partitioned based on the `locale`. So if you create two `Database`s with two different `locale`s, it will store twice as much data.
Also note that, unlike the picker, the database does not filter emoji based on whether they are supported by the current browser/OS or not. To detect emoji support, you can use a library like [is-emoji-supported](https://github.com/koala-interactive/is-emoji-supported).
The reason for this is that `Picker` automatically registers itself as a custom element, following [web component best practices](https://justinfagnani.com/2019/11/01/how-to-publish-web-components-to-npm/). But this adds side effects, so bundlers like Webpack and Rollup do not tree-shake as well, unless the modules are imported from completely separate files.
### Within a meta-framework (Next.js, SvelteKit, etc.)
Some meta-frameworks will attempt to server-side render (SSR) any dependencies you `import`. However, `emoji-picker-element` only supports client-side rendering – it does not work on the server side. If you attempt to import it on the server side, you will see an error like `requestAnimationFrame is not defined`.
To load `emoji-picker-element` only on the client side, use your meta-framework's technique for client-side-only imports. For example, you can use [dynamic `import()`s](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) with [`next/dynamic` in Next.js](https://stackoverflow.com/a/61881528/680742) or [`onMount()` in SvelteKit](https://www.banjocode.com/post/svelte/client-side-library).
`emoji-picker-element` is not designed for SSR. In most apps, an emoji picker should be lazy-loaded upon user interaction (for example, when the user clicks a button).
For optimal cache performance, it's recommended that your server expose an `ETag` header. If so, `emoji-picker-element` can avoid re-downloading the entire JSON file over and over again. Instead, it will do a `HEAD` request and just check the `ETag`.
If the server hosting the JSON file is not the same as the one containing the emoji picker, then the cross-origin server will also need to expose `Access-Control-Allow-Origin: *` and `Access-Control-Allow-Headers: ETag` (or `Access-Control-Allow-Headers: *` ). `jsdelivr` already does this, which is partly why it is the default.
Note that [Safari does not currently support `Access-Control-Allow-Headers: *`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers#Browser_compatibility), but it does support `Access-Control-Allow-Headers: ETag`.
If `emoji-picker-element` cannot use the `ETag` for any reason, it will fall back to the less performant option, doing a full `GET` request on every page load.
### emojibase-data compatibility (deprecated)
_**Deprecated:** in v1.3.0, `emoji-picker-element` switched from [`emojibase-data`](https://github.com/milesj/emojibase) to
[`emoji-picker-element-data`](https://npmjs.com/package/emoji-picker-element-data) as its default data source. You can still use `emojibase-data`, but only v5 is supported, not v6. Support may be removed in a later release._
When using `emojibase-data`, you must use the _full_ [`emojibase-data`](https://github.com/milesj/emojibase) JSON file, not the "compact" one (i.e. `data.json`, not `compact.json`).
### Trimming the emoji data (deprecated)
_**Deprecated:** in v1.3.0, `emoji-picker-element` switched from [`emojibase-data`](https://github.com/milesj/emojibase) to
[`emoji-picker-element-data`](https://npmjs.com/package/emoji-picker-element-data) as its default data source. With the new `emoji-picker-element-data`, there is no need to trim the emoji down to size. This function is deprecated and may be removed eventually._
If you are hosting the `emojibase-data` JSON file yourself and would like it to be as small as possible, then you can use the utility `trimEmojiData` function:
`emoji-picker-element` uses a "stale while revalidate" strategy to update emoji data. In other words, it will use any existing data it finds in IndexedDB, and lazily update via the `dataSource` in case that data has changed. This means it will work [offline-first](http://offlinefirst.org/) the second time it runs.
If you would like to manage the database yourself (e.g. to ensure that it's correctly populated before displaying the `Picker`), then create a new `Database` instance and wait for its `ready()` promise to resolve:
`emoji-picker-element` has a hard requirement on [IndexedDB](https://developer.mozilla.org/en-US/docs/Glossary/IndexedDB), and will not work without it.
For browsers that don't support IndexedDB, such as [Firefox in private browsing mode](https://bugzilla.mozilla.org/show_bug.cgi?id=1639542), you can polyfill it using [fake-indexeddb](https://github.com/dumbmatter/fakeIndexedDB). Here is [a working example](https://bl.ocks.org/nolanlawson/651e6fbe4356ff098f505e6cc5fb8cd8) and [more details](https://github.com/nolanlawson/emoji-picker-element/issues/9).
For Node.js environments such as [Jest](https://jestjs.io/) or [JSDom](https://github.com/jsdom/jsdom), you can also use fake-indexeddb. A [working example](https://github.com/nolanlawson/emoji-picker-element/blob/39c50c3ce4c4c4d2cd8a15f337a722ad86c739e9/config/jest.setup.js#L28-L29) can be found in the tests for this very project.
The [`emojibase-data`](https://github.com/milesj/emojibase) English JSON file is [854kB](https://unpkg.com/browse/emojibase-data@5.0.1/en/), and the "compact" version is still 543kB. That's a lot of data to keep in memory just for an emoji picker. And it's not as if that number is ever going down; the Unicode Consortium keeps adding more emoji every year.
3. If you want, you can even [load the IndexedDB data in a web worker](https://github.com/nolanlawson/emoji-picker-element/blob/ff86a42/test/adhoc/worker.js), keeping the main thread free from non-UI data processing.
To avoid downloading a large sprite sheet or font file – which may look out-of-place on different platforms, or may have [IP issues](https://blog.emojipedia.org/apples-emoji-crackdown/) –`emoji-picker-element` only renders native emoji by default. This means it is limited to the emoji font actually installed on the user's device.
To avoid rendering ugly unsupported or half-supported emoji, `emoji-picker-element` will automatically detect emoji support and only render the supported characters. (So no empty boxes or awkward double emoji.) If no color emoji are supported by the browser/OS, then an error message is displayed (e.g. older browsers, some odd Linux configurations).
Plus, embedding the JSON directly would mean re-parsing the entire object on second load, which is something we want to avoid since the data is already in IndexedDB.
`emoji-picker-element` only supports the latest versions of Chrome, Firefox, and Safari, as well as equivalent browsers (Edge, Opera, etc.). If you need support for older browsers, you will need polyfills for the following things (non-exhaustive list):