frimousse
A lightweight, unstyled, and composable emoji picker for React with virtualized rendering and auto-updating emoji data.
Repository Health
Technical Analysis
Frimousse is a React emoji picker built as a set of composable, unstyled parts — Root, Search, Viewport, List, Loading, Empty — that you assemble and style yourself with Tailwind, CSS-in-JS, or plain classes. It ships with no runtime dependencies, is tree-shakable, and virtualizes the emoji grid so only visible rows are rendered, keeping re-renders minimal even with thousands of emoji.
Rather than bundling a static emoji dataset, Frimousse fetches the latest Emojibase data on demand and caches it in local/session storage, re-validating with ETags so repeat visits skip the network round trip. It automatically detects which emoji a user’s platform can render (hiding unsupported glyphs like tofu boxes) and supports 25+ locales, skin tone selection, and keyboard navigation out of the box.
For teams already using shadcn/ui, Frimousse also ships as an installable component via the shadcn CLI, pre-wired to shadcn’s design tokens. It was originally built internally for the Liveblocks Comments default UI before being extracted into its own standalone package.
What You Get
- Unstyled, composable
EmojiPicker.*parts (Root, Search, Viewport, List, Loading, Empty, ActiveEmoji, SkinToneSelector) you assemble into your own markup - Automatic Emojibase data fetching with localStorage/sessionStorage caching and ETag-based revalidation, so data loads once and stays fresh
- Built-in virtualization of the emoji grid — only visible rows render, keeping the picker fast even with the full emoji set loaded
- Automatic hiding of emoji unsupported on the current platform, avoiding blank tofu-box glyphs
- Skin tone selection and 25+ locale support driven by Emojibase’s messages dataset
- A pre-built shadcn/ui component installable via
npx shadcn add, pre-wired to shadcn’s design tokens
Common Use Cases
- Adding an emoji picker to a chat, comment box, or reaction UI without pulling in a heavyweight, pre-styled picker library
- Building a custom-styled emoji picker inside a design system by composing Frimousse’s unstyled parts with existing component primitives (e.g. a Popover)
- Shipping a shadcn/ui-based app that needs an emoji picker matching the rest of the app’s shadcn tokens, installed directly via the shadcn CLI
- Supporting international users with locale-aware emoji labels/search and skin-tone-specific emoji rendering
Under The Hood
Architecture
Frimousse is organized as a small monorepo (root package plus a site/ documentation app, wired together with Turborepo) with a clear internal layering: src/data/ handles fetching, parsing, and searching Emojibase datasets (emoji.ts, emoji-picker.ts), src/store.ts/src/utils/store.tsx implement a small custom pub/sub store with batched, rAF-scheduled updates and React context/selector hooks, and src/components/emoji-picker.tsx composes both into the public compound-component API (EmojiPicker.Root, .Search, .Viewport, .List, etc.) using forwardRef and a dedicated EmojiPickerDataHandler that fetches data in an effect and feeds it into the store off the main thread via requestIdleCallback. This separation means data-fetching/caching, state, and rendering can each be reasoned about independently.
Tech Stack
The package itself has zero runtime dependencies — only React and TypeScript as peer dependencies — and is built with tsup into dual ESM/CJS output with generated type declarations. Development tooling is Biome for linting/formatting, Vitest (in both jsdom and Playwright-driven browser modes) for tests, and publint/arethetypeswrong for package-export correctness checks. The documentation site under site/ is a separate Next.js-based workspace consuming the built package as a live playground.
Code Quality
The repository documents 95%+ test coverage and backs that with an extensive __tests__ suite covering data parsing, search scoring, the custom store, storage helpers, and browser-only behaviors (emoji-support detection) via Vitest’s browser mode with real Chromium through Playwright. TypeScript is configured in strict mode with noUncheckedIndexedAccess, noUnusedLocals/Parameters, and verbatimModuleSyntax, and CI runs type-checking, Biome linting, and package-export validation on every change (.github/workflows/tests.yml), plus continuous preview releases via pkg.pr.new on every PR.
API Design
The public surface is deliberately small: a single EmojiPicker namespace export composed of a handful of primitive parts, each accepting standard HTML props plus a few picker-specific ones (locale, columns, skinTone, onEmojiSelect). Consumers get sensible defaults (English locale, 9 columns, no skin tone) and can override just what they need, with full TypeScript types exported for every prop shape. The shadcn CLI installation path lowers the barrier further for a large existing audience, and the parts expose [frimousse-*] data attributes as a built-in styling hook for consumers who don’t want to write custom class logic.
Used by 4 apps in this directory
Dub
Marketing · Analytics
The open-source link attribution platform for short links, conversion tracking, and affiliate programs — powering 100M+ clicks monthly.
Metabase
Analytics
The open-source BI platform that lets anyone ask questions and build dashboards without writing SQL — with an embedded analytics SDK and AI-powered query assistant included.
Plane
Productivity · Project Management · Collaboration
Open-source project management platform to replace Jira, Linear, and ClickUp — with built-in cycles, real-time collaborative docs, and full self-hosting.
PostHog
Analytics · Monitoring · Developer Tools
The all-in-one open source product platform combining analytics, session replay, feature flags, error tracking, AI observability, and a built-in data warehouse in a single self-hostable stack.