emoteer

Custom emojis

Add your own image-based emotes alongside the Unicode set

Emoteer ships the full Unicode emoji set by default. You can extend it with your own image-based emotes ("custom emotes") by passing a locals array to the EmoteProvider.

Adding custom emotes

Each entry is a LocalEmote:

interface LocalEmote {
  id: string;         // stable identifier — used as the React key
  name: string;       // display name, also the shortcode (without colons)
  src: string;        // URL or local path to the image
  category?: string;  // optional free-form label, indexed for search
}

Pass them to the provider:

app/layout.tsx
import { EmoteProvider } from '@emoteer/react';

const locals = [
  { id: 'party-parrot', name: 'party_parrot', src: '/emotes/party-parrot.gif' },
  { id: 'emoteer', name: 'emoteer', src: '/emotes/brand.png', category: 'brand' },
];

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <EmoteProvider locals={locals}>
      {children}
    </EmoteProvider>
  );
}

Where they show up

ComponentSupport
EmoteList.Grid✅ Rendered under a "Custom" section at the top.
EmoteList.Tabs✅ "Custom" tab appears when locals.length > 0.
EmoteList.Search✅ Matches against name and category.
EmoteList.Preview✅ Image preview; copy button writes :name: to clipboard; can be favourited.
EmoteAutocomplete✅ Suggested when typing :<name> — selecting inserts :name: (not a glyph).
EmoteInput / EmoteTextArea❌ <input> / <textarea> can't embed images. :name: is preserved verbatim.
ReactionCounter / ReactionButton❌ These accept raw emoji strings, not emotes. Pass the emoji/glyph directly and render an <img> yourself if needed.

Reading the selection

All picker/autocomplete onSelect callbacks now fire with an Emote union — native or local. Use the isLocalEmote helper to branch:

import { EmoteList, isLocalEmote, type Emote } from '@emoteer/react';

function Picker() {
  const handleSelect = (emote: Emote) => {
    if (isLocalEmote(emote)) {
      insertImage(emote.src);      // render your own <img>
    } else {
      insertText(emote.unicode);   // native glyph
    }
  };

  return (
    <EmoteList.Root onSelect={handleSelect}>
      <EmoteList.Search />
      <EmoteList.Tabs />
      <EmoteList.Grid />
      <EmoteList.Preview />
    </EmoteList.Root>
  );
}

Shortcode collisions

If a local name collides with a native shortcode (e.g. you define name: "smile"), the local wins — locals are inserted into the shortcode index after natives, so the last writer wins.

Disabling natives

If you want a brand-only picker with no Unicode emojis, set natives={false}:

<EmoteProvider natives={false} locals={locals}>
  {children}
</EmoteProvider>

Localising shortcodes

Pass a BCP 47 locale to load a different native shortcode dictionary:

<EmoteProvider locale="es" locals={locals}>
  {children}
</EmoteProvider>

Bundled locales include en, en-gb, es, es-mx, fr, de, it, ja, ko, pt, zh, zh-hant, and many more. Unsupported tags fall back to en at runtime.

On this page