Lynx/Modules/Emoji Picker/EmojiPicker
@sigx/lynx-emoji · Stable · Component library

EmojiPicker#

The full headless emoji picker: a search row, a category tab bar over one continuous scroll of sticky-headed sections, a skin-tone long-press popover and a recents section. Unstyled beyond neutral inline fallbacks — theme it via classes, render props or a themed wrapper. Pure JS, identical on iOS and Android.

Import#

TSX
import { EmojiPicker } from '@sigx/lynx-emoji';

Basic usage#

Give EmojiPicker a dataset and an onPick handler. Because it is a flex column, it must live in a bounded-height container — without a concrete height ceiling it resolves to zero height and nothing renders. The enData binding is the bundled English dataset (re-exported from the root); pass your own locale from @sigx/lynx-emoji/data/<locale> to tree-shake it away.

TSX
import { EmojiPicker, enData } from '@sigx/lynx-emoji';

function ReactionPicker({ onInsert }: { onInsert: (glyph: string) => void }) {
  return (
    <view style={{ height: '360px' }}>
      <EmojiPicker
        data={enData}
        onPick={({ glyph }) => onInsert(glyph)}
      />
    </view>
  );
}

The onPick payload is an EmojiPickEvent carrying the datum, the tone-resolved glyph to insert, and the active tone. data is optional with an EmojiProvider in scope and required without — it is fixed at mount, and the picker throws if neither a data prop nor a provider is available.

Layout and labels#

columns, cellSize, showRecents, showSearch, searchPlaceholder, recentsLabel and emptyLabel tune the surface without touching the theme. By default the grid sizes itself to its container — it derives a column count from the available width and a matching cell size, resolved once at mount as an atomic pair; pass columns or cellSize to pin either half. emptyLabel shows when the current slice is empty.

TSX
import { EmojiPicker, enData } from '@sigx/lynx-emoji';

function CompactPicker({ onInsert }: { onInsert: (glyph: string) => void }) {
  return (
    <view style={{ height: '320px' }}>
      <EmojiPicker
        data={enData}
        columns={9}
        cellSize={24}
        showRecents
        searchPlaceholder="Find an emoji"
        emptyLabel="No matches"
        onPick={({ glyph }) => onInsert(glyph)}
      />
    </view>
  );
}

Sections and the tab bar#

The picker is one continuous scroll over every category, each introduced by a sticky full-span header. Tapping a category tab scrolls to that section (the grid never re-mounts), and the active tab follows as you scroll. Recents are the first section — snapshotted per mount and hidden when empty; set its label with recentsLabel. Style the sticky headers through the sectionHeader slot in classes — the headless fallback has no background, so a theme should give it one.

Mounting is non-blocking: the first viewports of glyphs stage synchronously and the rest stream in over the following frames, so opening the picker never janks keyboard input, and cold-start recents hydrate before the snapshot.

Theming#

The picker is headless with neutral inline-style fallbacks only. There are two theming surfaces: the classes slot map (EmojiSlotClassesroot, search, grid, sectionHeader, cell, and so on) and the three render props (renderCell, renderCategoryTab, renderSearchInput). When a class is supplied for a slot, that slot's inline fallback style is dropped. @sigx/lynx-daisyui ships a ready-made skin.

TSX
import { EmojiPicker, enData } from '@sigx/lynx-emoji';
import { EmojiPickerSheet, emojiClasses } from '@sigx/lynx-daisyui';

function Themed({ insert }: { insert: (glyph: string) => void }) {
  return (
    <view style={{ height: '360px' }}>
      <EmojiPicker
        data={enData}
        classes={emojiClasses}
        onPick={({ glyph }) => insert(glyph)}
      />
    </view>
  );
}

A theme package can also extend props onto EmojiPickerProps by augmenting the empty EmojiPropsExtensions interface (the declare module '@sigx/lynx-emoji' pattern).

Sharing recents across surfaces#

With no provider in scope, EmojiPicker builds a private context from its data prop. When more than one picker surface exists, wrap them in an EmojiProvider so they share one dataset, search index, recents list and skin-tone preference. The provider wins over a local data prop, so the surfaces below need no data of their own.

TSX
import { EmojiProvider, EmojiPicker, enData } from '@sigx/lynx-emoji';

function Pickers({ insert }: { insert: (glyph: string) => void }) {
  return (
    <EmojiProvider data={enData} recentsCap={48}>
      <view style={{ height: '360px' }}>
        <EmojiPicker onPick={({ glyph }) => insert(glyph)} />
      </view>
    </EmojiProvider>
  );
}

For chat-composer and bottom-sheet presentations, prefer the KeyboardPanelPicker and SheetPicker wrappers, which size themselves and accept every EmojiPickerProps field except style and onPick.

Props#

PropTypeDescription
dataEmojiDataLocale dataset, fixed at mount. Optional with an EmojiProvider in scope, required without. Default: enData when imported.
columnsnumberGrid columns. Auto-sized from the container width by default; set it to pin a fixed count.
showRecentsbooleanShow the recents section and its tab. Default true.
showSearchbooleanShow the search row. Default true.
searchPlaceholderstringPlaceholder text for the search field.
recentsLabelstringLabel for the recents section / tab.
emptyLabelstringShown when the current slice is empty.
cellSizenumberGlyph cell size in px. Auto-sized to match the resolved column width by default; set it to pin a fixed size.
classesEmojiSlotClassesPer-slot class overrides (including the sectionHeader slot); supplying a slot class drops its inline fallback.
classstringExtra classes on the picker root.
styleRecord<string, string | number>Inline style on the picker root.
renderCellEmojiRenderCellReplaces a grid cell's content: (datum, glyph) => JSXElement.
renderCategoryTabEmojiRenderCategoryTabReplaces a category tab's content: (tab, glyph, active) => JSXElement.
renderSearchInputEmojiRenderSearchInputReplaces the whole search row, driven by an EmojiSearchApi.

Events#

EventTypeDescription
onPick(event: EmojiPickEvent) => voidFired when an emoji is picked. The payload carries datum, the tone-resolved glyph to insert, and the active tone.

See also#

  • API reference — every export, typed (EmojiPickerProps, EmojiPickEvent, the render-prop and theming types).
  • Usage — guides and complete examples, including the keyboard panel, bottom sheet and markdown integration.
  • EmojiProvider — share recents and skin tones across multiple picker surfaces.