picmo

A dependency-free, fully-accessible JavaScript emoji picker with search, skin-tone variants, and pluggable renderers for any framework.

Library
npm
v5.8.5
1,186stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
49/100Fair
Development Activity0
Maintenance44
Community52
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
68/100Good
Architecture78
Code Quality62
Innovation58
Learning Curve75

PicMo is a framework-agnostic emoji picker for the web, built as plain TypeScript with no React, Vue, or other UI-library dependency required. A single createPicker() call renders a fully-featured picker into any DOM element, complete with search, category tabs, recently-used tracking, skin-tone variant selection, and light/dark themes. Emoji and locale data come from the emojibase project and are fetched once from a CDN, then cached locally (IndexedDB by default, with an in-memory store as a fallback) so repeat loads skip the network entirely.

The project is split into three npm packages: the core picmo picker, @picmo/popup-picker for a button-triggered floating variant, and @picmo/renderer-twemoji for swapping in Twemoji graphics instead of the operating system’s native emoji glyphs. That renderer abstraction, plus a documented event API (emoji:select and friends), lets teams drop the same picker into a React, Vue, Svelte, or vanilla-JS app without re-implementing search, accessibility, or data loading each time.

What You Get

  • A framework-agnostic core picker (picmo) installable via npm, usable inline or embedded in any custom UI.
  • An optional @picmo/popup-picker package that wraps the core picker in a button-triggered floating popup.
  • An optional @picmo/renderer-twemoji renderer that swaps native OS emoji glyphs for consistent Twemoji graphics.
  • Full TypeScript type definitions, built-in light/dark themes, and an i18n bundle system for localized labels.
  • A locally cached emoji database (IndexedDB, with in-memory fallback) so the emoji dataset is fetched from a CDN once and reused across sessions.

Common Use Cases

  • Adding emoji reactions or composition to chat and messaging products.
  • Embedding an emoji picker in comment boxes or rich-text editors without pulling in a heavyweight UI kit.
  • Sharing one picker implementation across apps built on different frontend frameworks.
  • Rendering brand-consistent emoji graphics across operating systems via the Twemoji renderer.

Under The Hood

Architecture PicMo separates concerns into a ViewFactory that injects shared dependencies (an AppEvents event bus, an i18n Bundle, the active Renderer, and a lazily-resolved DataStore promise) into a tree of View subclasses under src/views, each paired with its own .template.ts markup function and scoped .css file. Custom-element wrappers under src/elements sit on top of these views to expose them as web components, while createPicker() wires the factory together and kicks off emoji-data loading asynchronously, emitting a data:ready or error event rather than blocking picker construction. The data layer is abstracted behind a DataStore interface with swappable IndexedDbStore and InMemoryStore implementations selected via a DataStoreFactory, so storage backend is a pluggable dependency rather than a hard-coded choice. Overall this is a solid, deliberately layered design — factory-based dependency injection, an event-driven core, and a clean split between rendering, data, and view logic.

Tech Stack The core package is written in TypeScript and uses lit for its custom elements, emojibase as the source of emoji and locale data, and FontAwesome icon packages for chrome UI. The monorepo (three packages: picmo, @picmo/popup-picker, @picmo/renderer-twemoji) is orchestrated with Lerna and npm workspaces, built with Vite plus a separate tsc --declaration pass for type definitions and PostCSS for stylesheet bundling. A companion Docusaurus site and Storybook instance live alongside the packages for documentation and component demos. Continuous integration runs on GitHub Actions against a single pinned Node version.

Code Quality The core package has ESLint and Prettier configured and enforced in CI (npm run precommit runs lint, type-check, and test), and the codebase is fully typed with explicit interfaces for options, data records, and factories. Error handling favors an event-emission pattern (events.emit('error', ...)) over thrown exceptions for async data-loading failures. Test coverage is comparatively thin for the codebase’s size — only a handful of Jest test files exist directly under src/__tests__ and src/views/__tests__, with no tests found for several core modules like the view factory or data stores. Combined with an ‘inactive’ recent-activity signal (no commits in the last year at time of writing), this points to a maintained-but-slowing project rather than an actively hardened one.

What Makes It Unique PicMo’s main differentiator versus other JS emoji pickers is its explicit renderer abstraction: the same picker core can render native OS emoji glyphs or delegate to @picmo/renderer-twemoji for pixel-consistent cross-platform images, without changing any application code. Combined with lazily-loaded, CDN-cached emoji data (avoiding shipping the full emoji dataset in the JS bundle) and a genuinely framework-agnostic core, it targets teams that want one emoji-picker implementation reusable across React, Vue, and vanilla-JS surfaces rather than a component tied to one framework’s ecosystem.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search