Frimousse API Reference

This file is the package-level API reference for @slithy/frimousse.

It covers:

Packages

Entry Points

Namespace export

import { EmojiPicker } from "@slithy/frimousse";

Available parts:

Preferred consumer-facing types

If you are building on the additive API, start from these public aliases rather than the lower-level internal type names:

Those are the stable consumer-facing types used throughout the docs below.

Named exports

import {
  buildEmojiPickerFrequentSection,
  buildNativeSearchTermsMap,
  createCustomEmoji,
  createCustomSection,
  createSupplementalItem,
  createSupplementalSection,
  formatAsShortcode,
  getEmojiPrimaryShortcode,
  getEmojiShortcodes,
  getEmojiPickerUsageKey,
  isCustomEmoji,
  isNativeSelection,
  isSupplementalSelection,
  rankEmojiPickerUsage,
  recordEmojiPickerUsage,
  sanitizeEmojiPickerUsageEntries,
  useActiveEmoji,
  useActiveItem,
  useSkinTone,
} from "@slithy/frimousse";

Native Search Helpers

buildNativeSearchTermsMap(entries)

Builds a search.native.terms map from app-owned or companion-package metadata.

type NativeSearchTermSource = {
  emoji: string;
  shortcodes?: string[];
  aliases?: string[];
  terms?: string[];
};

Notes:

formatAsShortcode(value)

Formats a display label into a normalized shortcode-like token.

Notes:

getEmojiShortcodes(source, options?)

Returns normalized shortcode-like display tokens for an item or widened item selection.

Notes:

getEmojiPrimaryShortcode(source, options?)

Returns the first normalized shortcode-like display token for an item or widened item selection.

Useful for footer or preview UIs that want one canonical :shortcode: string.

Components

EmojiPicker.Root

Base provider and interaction boundary for the picker tree.

Props:

Prop Type Default Notes
onEmojiSelect (emoji: Emoji) => void - Called when a native emoji is selected.
onItemSelect (selection: ItemSelection) => void - Called when any picker item is selected, including supplemental items. Additive; does not replace onEmojiSelect.
locale Locale "en" Emojibase locale.
skinTone SkinTone "none" Initial skin tone.
columns number 9 Number of visible list columns.
emojiVersion number browser-supported latest Restricts visible emoji by Emoji version.
emojibaseUrl string "https://cdn.jsdelivr.net/npm/emojibase-data" Base URL used to fetch Emojibase JSON datasets. Point this at your own hosted emojibase-data files when you want a self-hosted or offline-capable setup.
sticky boolean true Makes category headers sticky.
supplemental SupplementalConfig - Adds consumer-owned sections and supplemental search behavior.
search EmojiPickerSearchConfig - Adds native search enrichment data.
searchValue string - Controls the picker search value at the root level, including use cases that do not render EmojiPicker.Search.
onSearchValueChange (search: string) => void - Called whenever the picker search value changes. Useful with an external input or autocomplete field.

Built-in element props:

Attributes:

CSS variables:

Self-hosting with emojibaseUrl

@slithy/frimousse does not bundle the native emoji dataset into the package. By default it fetches emojibase-data JSON at runtime, but you can stage and host those files yourself.

Use the included staging helper:

pnpm exec frimousse-stage-emojibase-data --out ./public/emojibase-data

For multiple locales:

pnpm exec frimousse-stage-emojibase-data --out ./public/emojibase-data --locales en,fr,ja

Then point emojibaseUrl at that hosted path:

<EmojiPicker.Root locale="en" emojibaseUrl="/emojibase-data">
  <EmojiPicker.Search />
  <EmojiPicker.Viewport>
    <EmojiPicker.Loading>Loading…</EmojiPicker.Loading>
    <EmojiPicker.Empty>No emoji found.</EmojiPicker.Empty>
    <EmojiPicker.List />
  </EmojiPicker.Viewport>
</EmojiPicker.Root>

With that setup, the picker no longer depends on the public CDN. If your app can serve those files offline, the picker can work offline too.

EmojiPicker.Search

Search input for the picker.

Notes:

Built-in element props:

Attributes:

EmojiPicker.Viewport

Scrollable viewport for loading, empty, and list content.

Built-in element props:

Attributes:

EmojiPicker.List

Virtualized list renderer for categories, rows, and emoji buttons.

Props:

Prop Type Default Notes
components Partial<EmojiPickerListComponents> - Replaces internal renderers for category headers, rows, native emoji buttons, and supplemental emoji buttons.

Built-in element props:

Attributes:

EmojiPickerListComponents shape:

Inner components:

EmojiPicker.Loading

Rendered while emoji data is loading.

Built-in element props:

Attributes:

EmojiPicker.Empty

Rendered when the current search has no results.

Props:

Prop Type Notes
children ReactNode | ((props: EmojiPickerEmptyRenderProps) => ReactNode) Can be static content or a render callback.

Built-in element props:

Attributes:

EmojiPickerEmptyRenderProps:

EmojiPicker.SkinToneSelector

Built-in skin tone toggle button.

Props:

Prop Type Default Notes
emoji string "✋" Emoji used as the visual basis for skin tone variations.

Notes:

Built-in element props:

Attributes:

EmojiPicker.ActiveEmoji

Render-prop component for the currently active native emoji.

Props:

Prop Type Notes
children (props: EmojiPickerActiveEmojiRenderProps) => ReactNode Native-only active item surface.

EmojiPickerActiveEmojiRenderProps:

Prefer this when your UI is intentionally native-only.

EmojiPicker.ActiveItem

Render-prop component for the currently active item, including supplemental items.

Props:

Prop Type Notes
children (props: EmojiPickerActiveItemRenderProps) => ReactNode Widened active-item surface.

EmojiPickerActiveItemRenderProps:

Prefer this for any picker that may include supplemental items now or later.

EmojiPicker.SkinTone

Render-prop component for the current skin tone state.

Props:

Prop Type Default Notes
emoji string "✋" Emoji used to derive the variation list.
children (props: EmojiPickerSkinToneRenderProps) => ReactNode Render callback.

EmojiPickerSkinToneRenderProps:

Hooks

useActiveEmoji()

Returns the currently active native emoji, or undefined.

const activeEmoji = useActiveEmoji();

Return type:

Notes:

useActiveItem()

Returns the currently active item, including supplemental items.

const activeItem = useActiveItem();

Return type:

Notes:

useSkinTone(emoji = "✋")

Returns skin tone state, setter, and skin tone variations for the provided emoji.

const [skinTone, setSkinTone, skinToneVariations] = useSkinTone();

Return type:

Additive Supplemental API

The additive contract is centered on a few concepts:

supplemental root prop

EmojiPickerRootProps["supplemental"] accepts:

type SupplementalConfig = {
  sections?: Section[];
  search?: SupplementalSearch;
};

Use SupplementalConfig, Section, Item, and ItemSelection as the consumer-facing additive types.

SupplementalSearch:

Prop Type Default Notes
mode "grouped" | "unified" "grouped" Grouped mode preserves native category headings and matching supplemental section labels; unified mode merges everything into one results section.
resultsLabel string - Label used for unified result sections only. Ignored in grouped mode.
weights SupplementalSearchWeights built-in relevance defaults Overrides how strongly label, aliases, keywords, tags, and id contribute to supplemental match ranking. Applies to supplemental items only.

Grouped-mode guarantees:

Unified-mode guarantees:

Items, sections, and item selections

type NativeItem = {
  kind: "native";
  id: string;
  emoji: string;
  label: string;
};

type SupplementalItem = {
  kind: "supplemental";
  id: string;
  label: string;
  imageUrl?: string;
  tags?: string[];
  keywords?: string[];
  aliases?: string[];
  data?: unknown;
};

type Item =
  | NativeItem
  | SupplementalItem;

type Section = {
  id: string;
  label?: string;
  position?: "prepend" | "append";
  items: Item[];
  searchable?: boolean;
};

type NativeItemSelection = {
  kind: "native";
  item: NativeItem;
};

type SupplementalItemSelection = {
  kind: "supplemental";
  item: SupplementalItem;
};

type ItemSelection =
  | NativeItemSelection
  | SupplementalItemSelection;

searchable behavior:

Selection guards

isNativeSelection(selection)
isSupplementalSelection(selection)

Use these to narrow ItemSelection unions safely.

Supplemental Item Helpers

createSupplementalItem(input)

Creates a normalized supplemental item.

Input type:

type SupplementalItemInput = {
  id: string;
  label?: string;
  shortcode?: string;
  imageUrl?: string;
  tags?: string[];
  keywords?: string[];
  aliases?: string[];
  data?: unknown;
};

Field semantics:

Recommended mental model:

Common patterns:

  1. Shortcode-first custom emoji
{
  id: "shipit",
  label: "Ship It",
  shortcode: ":shipit:",
  aliases: ["ship-it", ":ship_it:"],
}

Use this when the shortcode-like name is the stable identity your app stores or exchanges.

  1. Plain supplemental item with search metadata
{
  id: "design-review",
  label: "Design review",
  imageUrl: "/emoji/design-review.png",
  keywords: ["review", "feedback"],
  tags: ["team"],
}

Use this when the item needs discoverability metadata but does not need a shortcode-oriented identity model.

Avoid treating these fields as interchangeable:

Built-in supplemental search treats label and aliases as name-like matches, keeps keywords and tags as weaker discovery signals, and treats an exact canonical id match as a first-class name-like hit in unified shortcode-first search.

SupplementalSearchWeights:

type SupplementalSearchWeights = {
  label?: number;
  aliases?: number;
  keywords?: number;
  tags?: number;
  id?: number;
};

Use this only to tune supplemental item ranking. Native emoji ranking still comes from the native dataset plus search.native.terms, with an opinionated built-in ranking policy rather than a public weighting API.

Set a weight to 0 when you want that field ignored entirely.

Return type:

createSupplementalSection(items, options)

Creates a normalized supplemental section that can contain plain or image-backed supplemental items.

Arguments:

SupplementalSectionOptions:

type SupplementalSectionOptions = {
  id: string;
  label?: string;
  position?: "prepend" | "append";
  searchable?: boolean;
};

Return type:

Custom Emoji Helpers

createCustomEmoji(input)

Creates a normalized image-backed supplemental item with required id and imageUrl.

Input type:

type CustomEmojiInput = {
  id: string;
  label?: string;
  imageUrl: string;
  tags?: string[];
  keywords?: string[];
  aliases?: string[];
  data?: unknown;
};

CustomEmojiInput keeps the same metadata semantics as SupplementalItemInput, but requires imageUrl.

Return type:

createCustomSection(items, options)

Creates a normalized section of image-backed custom emoji.

Arguments:

CustomSectionOptions:

type CustomSectionOptions = {
  id: string;
  label?: string;
  position?: "prepend" | "append";
  searchable?: boolean;
};

Return type:

isCustomEmoji(item)

Type guard for a supplemental item with a required imageUrl.

Frequency Helpers

Types

type EmojiPickerUsageSource = Item | ItemSelection;

type EmojiPickerUsageEntry = {
  key: string;
  item: Item;
  score: number;
  uses: number;
  lastUsedAt: number;
};

type EmojiPickerUsageOptions = {
  mode?: "frecency" | "recent";
  halfLifeMs?: number;
  maxEntries?: number;
  now?: Date | number;
};

type EmojiPickerFrequentSectionOptions = EmojiPickerUsageOptions & {
  id?: string;
  label?: string;
  limit?: number;
  position?: "prepend" | "append";
  searchable?: boolean;
};

getEmojiPickerUsageKey(source)

Returns a stable usage key in the form ${kind}:${id}.

rankEmojiPickerUsage(entries, options?)

Decays and sorts usage entries.

Behavior:

Return type:

recordEmojiPickerUsage(entries, source, options?)

Adds or updates a usage entry and returns the re-ranked collection.

Behavior:

Return type:

sanitizeEmojiPickerUsageEntries(value)

Sanitizes persisted usage-entry data from consumer-owned storage.

Behavior:

Typical use:

function readEmojiPickerUsageEntries() {
  if (typeof window === "undefined") {
    return [];
  }

  try {
    const raw = window.localStorage.getItem("emoji-picker-usage");

    return sanitizeEmojiPickerUsageEntries(raw ? JSON.parse(raw) : []);
  } catch {
    return [];
  }
}

Return type:

buildEmojiPickerFrequentSection(entries, options?)

Builds a frequent-items section from ranked usage.

This uses the same frecency ranking as rankEmojiPickerUsage, then takes the top limit items and turns them into a supplemental section.

Use mode: "recent" when you want a “Recently used” section instead.

Return type:

Defaults:

Search Configuration

EmojiPickerRootProps["search"] accepts:

type EmojiPickerNativeSearchConfig = {
  terms?: Record<string, string[]>;
};

type EmojiPickerSearchConfig = {
  native?: EmojiPickerNativeSearchConfig;
};

Use this to enrich native emoji matching with consumer-owned search terms.

Styling Hooks

Stable styling hooks exposed on built-in parts:

Relevant state hook:

The implementation also uses internal measurement and sizing attributes. Treat those as implementation details unless documented elsewhere.

Exported Types

This section lists the types re-exported from the package entrypoint.

Core

Items and selections

Component props and render props

Custom emoji and sections

Frequency

Notes

Companion Package API Reference

The sections below cover optional companion packages. They are documented here for convenience, but they are separate installs and separate entry points.

@slithy/emoji-transforms

Install:

pnpm add @slithy/emoji-transforms

Purpose:

Boundary:

Entry point:

import {
  adaptNativeEmojiSearchEntries,
  adaptEmojibaseNativeEmojiSearchEntries,
  buildFallbackTermsFromEmojibase,
  buildNativeEmojiSearchTermMap,
  buildNativeEmojiSearchTermMapFromAdapter,
  buildNativeEmojiSearchTermMapFromEmojibase,
  mergeNativeEmojiSearchTermMaps,
  buildShortcodeMap,
  buildShortcodeMapFromAdapter,
  buildShortcodeMapFromEmojibase,
  buildShortcodeMapFromPreset,
  getNativeEmojiSearchTerms,
  getPrimaryShortcode,
  getShortcodes,
  normalizeNativeEmojiSearchKey,
} from "@slithy/emoji-transforms";

Search term and shortcode builders

buildNativeEmojiSearchTermMap(entries)

Builds a plain Record<string, string[]> keyed by normalized base emoji.

Input shape:

type NativeEmojiShortcodeEntry = {
  emoji: string;
  shortcodes?: readonly string[];
  aliases?: readonly string[];
};

Notes:

buildShortcodeMap(entries)

Builds a shortcode-only Record<string, string[]> keyed by normalized base emoji.

Notes:

buildNativeEmojiSearchTermMapFromAdapter(entries, adapter)

Combines an adapter step with native-search map construction.

buildShortcodeMapFromAdapter(entries, adapter)

Combines an adapter step with shortcode-map construction.

adaptNativeEmojiSearchEntries(entries, adapter)

Maps arbitrary source records into the package’s neutral NativeEmojiShortcodeEntry format.

adaptEmojibaseNativeEmojiSearchEntries(entries, options?)

Adapts a common Emojibase-like record shape into the package’s neutral entry format.

buildFallbackTermsFromEmojibase(entries, options?)

Builds a native-search term map from a secondary Emojibase locale dataset for fallback search use cases.

Notes:

Build-time example:

// scripts/build-fr-search-terms.ts
import { writeFile } from "node:fs/promises";
import englishData from "emojibase-data/en/data.json";
import frenchData from "emojibase-data/fr/data.json";
import {
  buildFallbackTermsFromEmojibase,
  buildNativeEmojiSearchTermMapFromEmojibase,
  mergeNativeEmojiSearchTermMaps,
} from "@slithy/emoji-transforms";

const searchTerms = mergeNativeEmojiSearchTermMaps(
  buildNativeEmojiSearchTermMapFromEmojibase(frenchData, {
    includeLabel: true,
  }),
  buildFallbackTermsFromEmojibase(englishData),
);

await writeFile(
  new URL("../src/generated/fr-search-terms.json", import.meta.url),
  `${JSON.stringify(searchTerms, null, 2)}\n`,
);

Run example:

pnpm tsx scripts/build-fr-search-terms.ts

That writes src/generated/fr-search-terms.json, which you can then pass to the picker:

import frSearchTerms from "./generated/fr-search-terms.json";

<EmojiPicker.Root
  locale="fr"
  search={{ native: { terms: frSearchTerms } }}
>
  {/* ... */}
</EmojiPicker.Root>;

buildNativeEmojiSearchTermMapFromEmojibase(entries, options?)

Builds a native-search term map directly from Emojibase-like records.

Notes:

mergeNativeEmojiSearchTermMaps(...maps)

Combines multiple plain native-search term maps into one normalized result.

Notes:

buildShortcodeMapFromEmojibase(entries)

Builds a shortcode-only map directly from Emojibase-like records.

buildShortcodeMapFromPreset(entries, preset)

Joins Emojibase records with a hexcode-keyed shortcode preset such as emojibase-data/en/shortcodes/iamcal.json.

Use this when your app treats a preset like iamcal as the source of truth for native shortcode names.

Lookup helpers

getNativeEmojiSearchTerms(termMap, emoji)

Performs normalized lookup against a native-search term map.

getShortcodes(shortcodeMap, emoji)

Performs normalized lookup against a native shortcode map.

getPrimaryShortcode(shortcodeMap, emoji)

Returns the first normalized shortcode for that emoji.

normalizeNativeEmojiSearchKey(emoji)

Exposes the base-key normalization used by the package.

Normalization behavior:

Exported types

@slithy/emoji-compat

Install:

pnpm add @slithy/emoji-compat

Purpose:

Boundary:

Entry point:

import {
  buildCompatMap,
  detectSupportedVersion,
  getCompatEntry,
  getFallbackUrl,
  isEmojiSupported,
  normalizeEmojiCompatKey,
} from "@slithy/emoji-compat";

Build-time asset helpers:

import {
  buildFallbackAssetManifest,
  collectFallbackHexcodes,
  downloadFallbackAssets,
} from "@slithy/emoji-compat/assets";

Runtime helpers

buildCompatMap(records, options?)

Builds fallback metadata keyed by native emoji strings.

Input shape:

type EmojiCompatRecord = {
  emoji: string;
  version: number;
  hexcode?: string;
  skins?: readonly {
    emoji: string;
    hexcode?: string;
  }[];
};

Notes:

detectSupportedVersion(records, options?)

Determines the highest emoji version supported by the current browser across the provided records.

isEmojiSupported(emoji)

Low-level native-support probe for one emoji glyph.

getCompatEntry(compatMap, emoji)

Looks up one compat entry by normalized emoji key.

getFallbackUrl(compatMap, emoji, options?)

Returns a fallback asset URL when the emoji needs image fallback rendering.

Default convention:

normalizeEmojiCompatKey(emoji)

Exposes the normalization used for compat-map storage and lookup.

Build-time asset helpers

buildFallbackAssetManifest(records, options)

Builds a stable manifest of fallback assets needed above a chosen versionFloor.

collectFallbackHexcodes(records, options)

Returns just the normalized lowercase hexcodes from that manifest.

downloadFallbackAssets(manifest, options)

Downloads matching fallback assets for a manifest.

Notes:

Exported types