FAQ

Practical answers for common frimousse questions.

The short version: @slithy/frimousse keeps the base picker lean and composable, adds useful extension seams, and leaves broader emoji metadata policy to companion packages.

Why this fork exists

Frimousse is a great base picker. @slithy/frimousse exists because I wanted to keep that lightweight, composable core while filling in some real-world extension seams that production apps tend to need, gaps that I ran into when I was trying to replace the abandoned emoji-mart library with Frimousse.

For me, that meant mixed native and custom emoji sections, richer search behavior, consumer-owned frequent items, and clearer paths for self-hosting emoji data and fallback rendering.

The result is still a headless picker, not a batteries-included widget. This FAQ covers the practical tradeoffs: what changed, what stayed the same, what remains consumer-owned, and when this picker is or is not the right fit.

At a glance

Topic@slithy/frimousse
Picker styleHeadless, composable React picker
Native emoji dataRuntime fetch by default, self-hostable with emojibaseUrl
Offline supportYes, when you stage and self-host the needed Emojibase files
Custom emojiYes, via supplemental and custom emoji helpers
Frequent or recent itemsConsumer-owned persistence, helper-supported ranking and section building
Native search enrichmentVia @slithy/emoji-transforms
Fallback image policyVia @slithy/emoji-compat
Best fitApps that want control over styling, data delivery, and emoji policy

Why use @slithy/frimousse instead of upstream Frimousse?

Use the fork when you want to stay close to the original composition model, but you also need practical extension seams that upstream does not provide. See the EmojiPicker.Root APIfor the additive root-level surfaces.

Today that mainly means:

  • consumer-defined mixed sections
  • image-backed custom emoji helpers
  • unified search across native and supplemental items
  • widened selection surfaces for mixed pickers
  • consumer-owned frequent and recent item helpers

If you only need the baseline native-only picker and want the original package, upstream Frimousse remains a reasonable choice.

What is the main difference in practice?

The main difference is that this fork keeps Frimousse's base composition model, but extends it for production use cases that need to mix native and custom emoji, enrich search, and own more of the surrounding emoji policy. See EmojiPicker.Root, supplemental item helpers, and @slithy/emoji-transforms.

In other words, the picker is still intentionally lean, but it is no longer limited to a native-only story.

Do I need Tailwind?

No. @slithy/frimousse is headless and unstyled. You can style it with Tailwind, plain CSS, CSS-in-JS, or a design-system layer of your own. The relevant surfaces are the picker components and their built-in attributes and CSS variables.

Can I use it in a popover?

Yes. The package only provides the picker itself, not a trigger or popover primitive. In practice, that means you wrap the picker root in whatever popover, dialog, or floating-ui primitive your app already uses.

How does native emoji data delivery work?

@slithy/frimousse does not bundle the native emoji dataset into the package. By default it fetches Emojibase JSON at runtime, which keeps the picker lean and lets your app decide how that data should be delivered.

In practice, that means two things: the default setup uses the public Emojibase CDN, and offline support comes from hosting those same files yourself. The API reference covers that under self-hosting with emojibaseUrl.

That is a deliberate tradeoff. Instead of baking one data-delivery policy into the package, the picker exposes a simple contract and lets the consumer decide how strict, private, or self-contained the final app needs to be.

Can it work offline?

Yes. If you host the needed Emojibase files yourself and point EmojiPicker.Root at them, the picker no longer depends on the public CDN. See emojibaseUrl for the picker-side contract.

That is also the setup to use when you want tighter control over availability, privacy, CSP, or release timing.

Typical setup:

  1. Run pnpm exec frimousse-stage-emojibase-data --out ./public/emojibase-data.
  2. Serve the locale files your picker needs, such as data.json and messages.json.
  3. Point EmojiPicker.Root at that hosted directory with emojibaseUrl.
pnpm exec frimousse-stage-emojibase-data --out ./public/emojibase-data
import { EmojiPicker } from "@slithy/frimousse";

export function MyEmojiPicker() {
  return (
    <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.

Does this fork support custom emoji?

Yes. The fork adds supplemental-item helpers that let you mix native emoji and image-backed custom emoji in one picker. The relevant API surfaces are documented under supplemental item helpers and custom emoji helpers.

The core model is intentionally simple: native emoji remain dataset owned, while your app owns custom emoji identity, image URLs, search aliases, and persistence policy.

How do frequent or recent items work?

The library does not persist them for you. Instead, it gives you small helpers for recording usage, sanitizing stored entries, ranking them, and building a prepend section from the result. See the frequency helpers in the API reference.

That keeps storage and product policy in your app, while still covering the repetitive mechanics.

Can native emoji search use shortcodes or fallback terms?

Yes, but that metadata is companion-owned rather than bundled into the picker. Use @slithy/emoji-transforms to build native search-term maps or shortcode maps from Emojibase-style data, then pass the result into the picker. See @slithy/emoji-transforms.

That keeps the picker contract small while still supporting shortcode-first or locale-fallback applications.

What if a user's device does not support newer emoji yet?

That is what @slithy/emoji-compat is for. It gives you a ready-made path for detecting support gaps, resolving fallback metadata, and preparing the fallback assets needed for newer emoji on unsupported devices. See @slithy/emoji-compat in the API reference.

This is not really a picker concern. It addresses the broader product case where one user sends or stores an emoji that another user's device cannot natively display.

The package does not force a rendering layer on you, but it does cover the reusable mechanics so you do not have to invent them yourself. Your app still decides when to swap in an image, where those assets live, and what UI layer renders them.

What are the companion packages for?

@slithy/emoji-transforms handles data shaping for search and shortcode metadata.

@slithy/emoji-compat handles runtime support checks and fallback asset planning.

The picker itself stays focused on rendering, interaction, and composition. Broader emoji metadata policy lives outside the picker on purpose.

When should I choose something else?

Choose something else if you want a more opinionated, batteries-included picker with more UI already decided for you.

@slithy/frimousse is a better fit when you want a headless picker, control over styling, additive extension seams, and explicit ownership over data delivery, custom emoji, search metadata, and fallback policy.

It can work offline too, but that path is still consumer-owned: you stage the Emojibase files you need and host them where your app can serve them.