`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 changed with arbitrary CSS. Please refer to the API below for style customization.
For accessibility reasons, `emoji-picker-element` displays a prominent focus ring. If you want to hide the focus ring for non-keyboard users (e.g. mouse and touch only), then use the [focus-visible](https://github.com/WICG/focus-visible) polyfill, e.g.:
```css
.js-focus-visible :focus:not(.focus-visible) {
outline: none;
}
```
```js
import { applyFocusVisiblePolyfill } from 'focus-visible';
const picker = new Picker();
applyFocusVisiblePolyfill(picker.shadowRoot);
```
`emoji-picker-element` already ships with the proper CSS for both the `:focus_visible` standard and the polyfill.
## JavaScript API
### Picker
```js
import { Picker } from 'emoji-picker-element';
const picker = new Picker();
document.body.appendChild(picker);
```
`new Picker(options)` supports a few different options:
| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |
| `dataSource` | String | `"https://cdn.jsdelivr.net/npm/emojibase-data@5/en/data.json"` | Where to fetch the emoji data from. Note that `emoji-picker-element` requires the full `data.json`, not `compact.json`. |
| `locale` | String | `"en"` | Locale, should map to the locales supported by `emojibase-data` |
| `i18n` | Object | See below | Strings to use for internationalization of the Picker itself, i.e. the text and `aria-label`s. Note that `emoji-picker-element` only ships with English by default. |
These values can also be set at runtime, e.g.:
```js
const picker = new Picker();
picker.dataSource = '/my-emoji.json';
```
#### i18n structure
Here is the default English `i81n` object (`"en"` locale):
<!-- i18n options start -->
```json
{
"categories": {
"smileys-emotion": "Smileys and emoticons",
"people-body": "People and body",
"animals-nature": "Animals and nature",
"food-drink": "Food and drink",
"travel-places": "Travel and places",
"activities": "Activities",
"objects": "Objects",
"symbols": "Symbols",
"flags": "Flags"
},
"categoriesLabel": "Categories",
"emojiUnsupported": "Your browser does not support color emoji.",
"loading": "Loading…",
"networkError": "Could not load emoji. Try refreshing.",
"regionLabel": "Emoji picker",
"search": "Search",
"searchResultsLabel": "Search results",
"skinToneLabel": "Choose a skin tone"
}
```
<!-- i18n options end -->
Note that some of these strings are only visible to users of screen readers.
But you should still support them if you internationalize your app!
In general, it's not a problem to create multiple `Database` objects with the same arguments. Under the hood, they will share the same IndexedDB connection.
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.
`emoji-picker-element` requires the _full_ [emojibase-data](https://github.com/milesj/emojibase) JSON file, not the "compact" one. If you would like to trim the JSON file down even further, then you can modify the JSON to only contain these keys:
You can fetch the emoji JSON file from wherever you want. However, 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 fire off 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 cross-origin server will also need to expose `Access-Control-Allow-Origin: *` and `Access-Control-Allow-Headers: *`. (Note that `jsdelivr` already does this, which is why it is the default.)
Unfortunately [Safari does not support `Access-Control-Allow-Headers`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers#Browser_compatibility), meaning that the `ETag` header will not be available cross-origin. In that case, `emoji-picker-element` will fall back to the less performant option. If you want to avoid this, host the JSON on the same server as your web app.
`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:
Why IndexedDB? Well, 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.
1. We don't need to keep half a megabyte of emoji data in memory at all times.
2. The second time your visitors visit your website, we don't even need to download, parse, and index the emoji data, because it's already available on their hard drive.
To avoid downloading a large sprite sheet (which may look out-of-place on different platforms, or may have IP issues), `emoji-picker-element` only renders native emoji. This means it is limited to the emoji 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.)