emoteer

EmoteList

Searchable, virtualized emoji picker with tabs, keyboard navigation and preview

EmoteList is the compound picker. It ships a search input, category tabs, a virtualized grid and a preview panel. Every slot is an independent component β€” use them all, mix and match, or wrap them with your own markup.

Loading emojis…
Hover an emoji

Anatomy

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

Basic usage

components/picker.tsx
import { EmoteList, isLocalEmote } from '@emoteer/react';

export function Picker() {
  return (
    <EmoteList.Root
      onSelect={(emote) =>
        console.log(isLocalEmote(emote) ? `:${emote.name}:` : emote.unicode)
      }
      className="w-80 rounded-3xl border"
    >
      <EmoteList.Search />
      <EmoteList.Tabs />
      <EmoteList.Grid height={300} />
      <EmoteList.Preview />
    </EmoteList.Root>
  );
}

Slots

SlotDescription
RootContext provider. Handles selection and keyboard navigation.
SearchSearch input with debounced matching.
TabsCategory tabs. Switches the visible group.
GridVirtualized emoji grid.
PreviewShows the active emoji and its shortcode.

Props

EmoteList.Root

PropTypeDescription
onSelect(emote: Emote) => voidCalled when the user selects an emoji or a local emote. Narrow with isLocalEmote.
classNamestringForwarded to the outer container.

EmoteList.Search

PropTypeDescription
classNamestringForwarded to the outer container.

EmoteList.Tabs

PropTypeDefaultDescription
display"emoji" | "label""emoji"Show emoji icons or text labels.
classNamestringβ€”Forwarded to the outer container.

EmoteList.Grid

PropTypeDefaultDescription
heightnumber280Pixel height of the scrollable area.

EmoteList.Preview

PropTypeDescription
classNamestringForwarded to the outer container.

The preview slot shows the currently hovered emoji with its shortcode, a copy-to-clipboard button and a favorite toggle. Favorites are persisted to localStorage under emoteer-favorites and surface automatically in the grid as a dedicated tab.

Convenience export

EmoteListPicker wires every slot together with the default layout. Use it when you want a full picker without composing the pieces yourself.

components/picker.tsx
import { EmoteListPicker, isLocalEmote } from '@emoteer/react';

<EmoteListPicker
  onSelect={(emote) =>
    console.log(isLocalEmote(emote) ? `:${emote.name}:` : emote.unicode)
  }
/>;

Styling

Every slot accepts a className, and exposes a stable data-scope="emote-list" / data-part hook for headless styling. Theming flows through the --em-* CSS variables (each falling back to your app's own tokens) β€” override them in plain CSS or, optionally, a Tailwind theme. See Theming.

On this page