<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# Emoji

One emoji from an image catalogue, drawn as an `<img>` the size of the text around it, named by its `alt` (the emoji's name). An animated emoji shows its still image until it plays: while the mouse is on it or on the button around it, or that button has focus, or while `play` says so. Its animation is fetched once the still image has loaded, at low priority, so the first play starts at once; not for a still given `fetchPriority="low"`, nor while the browser asks to save data. With reduced motion it always shows the still image, and the animation is not fetched. `skinTone` draws an emoji with tones in one of them, and `placeholder` stands in until its picture has loaded. Its picture is fetched as soon as it is drawn, not when it nears the screen, so an emoji in an older message is there when the reader scrolls back to it. Its box is the text's size from the first frame, and a picture that fails to load keeps it, so no line moves as emoji load or fail.

```tsx
import { Emoji } from "@/components/ouro/emoji/emoji";
```

## Example

```tsx
<Emoji item={party} />
<Emoji item={party} placeholder="/emoji/waiting.svg" />
<Button variant="plain" aria-label="Party popper"><Emoji item={party} alt="" /></Button>
```

## Use instead when

- Use `EmojiText` instead to draw the emoji in a message's text, and an emoji character for an app that uses the platform's emoji font.

## Props

Type: `EmojiProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `alt` | `string` | the emoji's `name` | The image's text alternative. |
| `className` | `string` |  | Layout only: margins, and a size other than the text's (`size-8`). Appearance classes warn in development. |
| `item` (required) | `EmojiItem` |  | The emoji to draw, from the app's catalogue. |
| `placeholder` | `string \| ReactElement` |  | Shows in the emoji's place until its picture has loaded and decoded: an image's address, or an element (centred in the emoji's box, which it does not change). The picture then fades in over it, at once with reduced motion (the device's setting, or OuroProvider's `motion`). The placeholder is hidden from screen readers, so the emoji keeps its name, and a picture that fails to load or decode leaves it showing. It shows again for a new picture (another emoji, tone or `src`), not while an animated emoji plays. With it, the `<img>` sits in a `<span>` that takes `className`. |
| `play` | `boolean` |  | Plays an animated emoji now (`true`) or keeps it still (`false`). Without it, the emoji plays while the mouse is on it or on the button, link or option around it, or that has focus. Reduced motion keeps it still whatever this says. |
| `ref` | `Ref<HTMLImageElement>` |  | The `<img>`. |
| `skinTone` | `"default" \| "light" \| "medium-light" \| "medium" \| "medium-dark" \| "dark"` | `"default"` | The skin tone to draw it in, for an emoji with `skinTones`. |

## Native attributes

Also accepts the attributes in React's `HTMLAttributes` and `ImgHTMLAttributes` (`id`, `aria-*`, event handlers), passed to the rendered element, except those named on this page.

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `animate`: Not a prop. Ouro UI uses `play`: `<Emoji item={item} play />`.
- `emoji`: Not a prop. Emoji draws a catalogue's item, not text: `<Emoji item={catalogueItem} />`.
- `src`: Not a prop. The image comes from the catalogue's item: `<Emoji item={{ id, name, src }} />`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`). Your classes always win over Ouro UI's: Emoji merges `className` last with `cn` (tailwind-merge), so a class that conflicts with its own replaces it.[^layout-classes]

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.

## Types

### `EmojiFilmstrip`

An animation drawn as a filmstrip: square frames stacked top to bottom in one image, so the frames are the image's height over its width.

```ts
interface EmojiFilmstrip {
  /** The filmstrip image's address. */
  src: string;
  /** Frames a second. */
  fps: number;
}
```

### `EmojiItem`

One emoji in an image catalogue: its id, its name and the image that draws it. An app maps its own emoji set to this, whether a standard set or an organization's custom emoji.

```ts
interface EmojiItem {
  /** Identifies the emoji, unique in the catalogue: `"party"`. Reactions, recents and `:id:` tokens use it. */
  id: string;
  /** Its name, which is the image's `alt`, what screen readers hear and what the search matches first: `"Party popper"`. */
  name: string;
  /**
   * The still image's address. It shows whenever the emoji is not playing, and always with reduced motion.
   */
  src: string;
  /** Sizes of the still image for sharper screens, as `<img srcset>`: `"party-2x.png 2x"`. */
  srcSet?: string | undefined;
  /**
   * An animated image (GIF, animated WebP or PNG), which plays while the pointer is on the emoji
   * or on the button around it, or that button has focus. With reduced motion it never plays.
   */
  animatedSrc?: string | undefined;
  /**
   * The animation as a filmstrip, square frames stacked top to bottom in one image, for an
   * emoji without `animatedSrc`: while the emoji plays, it steps through the frames at `fps`;
   * otherwise, and always with reduced motion, `src` shows.
   */
  filmstrip?: EmojiFilmstrip | undefined;
  /** The still image's width in pixels, given to the `<img>` so the page keeps its shape while it loads. It shows at the text's size. */
  width?: number | undefined;
  /** The still image's height in pixels, as `width`. */
  height?: number | undefined;
  /** Short names typed between colons, without them: `["party", "tada"]`. The first makes the emoji's token, `:party:`. */
  shortcodes?: readonly string[] | undefined;
  /** More words the search matches: `["celebrate", "hooray"]`. */
  keywords?: readonly string[] | undefined;
  /**
   * The emoji as plain text, such as its Unicode character (`"🎉"`), for places an image cannot
   * go (a copied message, a notification). `EmojiText` finds it in messages and draws the image;
   * Ouro never draws it as text.
   */
  text?: string | undefined;
  /** It is the organization's or app's own emoji rather than one of the standard set. Ouro draws it the same; apps can label or treat it apart. */
  custom?: boolean | undefined;
  /**
   * The emoji in Unicode's five skin tones, light to dark; leave it out for an emoji without tones.
   */
  skinTones?: readonly EmojiItemTone[] | undefined;
}
```

### `EmojiItemTone`

An emoji's image in one skin tone: `skinTones` on an `EmojiItem`.

```ts
interface EmojiItemTone {
  /** Identifies the emoji in this tone, unique in the catalogue: `"thumbs-up-tone3"`. Reactions and tokens use it. */
  id: string;
  /** The still image's address. */
  src: string;
  /** Sizes of the still image for sharper screens, as `<img srcset>`: `"wave-2x.png 2x"`. */
  srcSet?: string | undefined;
  /** An animated image (GIF, animated WebP or PNG), shown while the emoji plays; the still one shows otherwise. */
  animatedSrc?: string | undefined;
  /** The animation as a filmstrip of square frames, played while the emoji plays, for a tone without `animatedSrc`. */
  filmstrip?: EmojiFilmstrip | undefined;
  /**
   * The emoji in this tone as text (`"👍🏽"`), which `EmojiText` finds in messages; Ouro never draws it as text.
   */
  text?: string | undefined;
}
```

[^layout-classes]: test:registry/ouro/components/ouro/emoji/emoji.test.tsx::Emoji > passes the img attributes and ref through, and lets app layout classes win verify:testExists(registry/ouro/components/ouro/emoji/emoji.test.tsx::Emoji > passes the img attributes and ref through, and lets app layout classes win)
