Skip to main content
The Emoji Picker component provides a user-friendly interface for browsing and selecting emojis. It includes search functionality, skin tone variants, categorized emoji lists, and is built using the Frimousse library by Liveblocks.

Installation

npx shadcn@latest add @eo-n/emoji-picker

Usage

Import the emoji picker components:
import {
  EmojiPicker,
  EmojiPickerContent,
  EmojiPickerSearch,
} from "@/components/ui/emoji-picker";
<EmojiPicker
  onEmojiSelect={({ emoji }) => {
    console.log(emoji);
  }}
>
  <EmojiPickerSearch />
  <EmojiPickerContent />
</EmojiPicker>

API Reference

EmojiPicker

The root container component for the emoji picker. Props
PropTypeDefaultDescription
onEmojiSelect(data: { emoji: string; label: string }) => void-Callback when an emoji is selected
columnsnumber8Number of emoji columns to display
defaultSkinTonenumber0Default skin tone (0-5)

EmojiPickerSearch

Search input for filtering emojis by name or keyword. Props Extends standard input props.
PropTypeDescription
placeholderstringPlaceholder text for the search input

EmojiPickerContent

Viewport container for the scrollable emoji list. Props Extends standard div props.

EmojiPickerFooter

Optional footer for displaying active emoji info and controls. Props Extends standard div props.

EmojiPickerSkinToneSelector

Button to open skin tone selection. Props
PropTypeDefaultDescription
emojistring"👋"Emoji to display on the selector button

EmojiPickerSkinTone

Inline skin tone selector with all variants. Props
PropTypeDefaultDescription
emojistring"👋"Emoji to show skin tone variants for

Examples

Basic Emoji Picker

Simple emoji picker with search:
import {
  EmojiPicker,
  EmojiPickerContent,
  EmojiPickerSearch,
} from "@/components/ui/emoji-picker";

export default function EmojiPickerDemo() {
  return (
    <EmojiPicker
      onEmojiSelect={({ emoji, label }) => {
        console.log(`Selected: ${emoji} ${label}`);
      }}
    >
      <EmojiPickerSearch />
      <EmojiPickerContent />
    </EmojiPicker>
  );
}

With Popover

Embed the emoji picker in a popover for better UX:
import { Button } from "@/components/ui/button";
import {
  EmojiPicker,
  EmojiPickerContent,
  EmojiPickerFooter,
  EmojiPickerSearch,
  EmojiPickerSkinToneSelector,
} from "@/components/ui/emoji-picker";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";

export default function EmojiPickerPopover() {
  return (
    <Popover>
      <PopoverTrigger render={<Button>Open emoji picker</Button>} />
      <PopoverContent className="w-fit p-0">
        <EmojiPicker
          onEmojiSelect={({ emoji, label }) => {
            console.log(`Selected: ${emoji} ${label}`);
          }}
        >
          <EmojiPickerSearch />
          <EmojiPickerContent />
          <EmojiPickerFooter>
            <EmojiPickerSkinToneSelector />
          </EmojiPickerFooter>
        </EmojiPicker>
      </PopoverContent>
    </Popover>
  );
}

With State Management

Manage selected emoji with React state:
import { useState } from "react";
import { Button } from "@/components/ui/button";
import {
  EmojiPicker,
  EmojiPickerContent,
  EmojiPickerSearch,
} from "@/components/ui/emoji-picker";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";

export default function EmojiPickerWithState() {
  const [selectedEmoji, setSelectedEmoji] = useState("");
  const [open, setOpen] = useState(false);

  return (
    <div className="flex flex-col gap-4">
      <Popover open={open} onOpenChange={setOpen}>
        <PopoverTrigger render={<Button>Select Emoji</Button>} />
        <PopoverContent className="w-fit p-0">
          <EmojiPicker
            onEmojiSelect={({ emoji }) => {
              setSelectedEmoji(emoji);
              setOpen(false);
            }}
          >
            <EmojiPickerSearch placeholder="Search emojis..." />
            <EmojiPickerContent />
          </EmojiPicker>
        </PopoverContent>
      </Popover>
      {selectedEmoji && (
        <div className="text-center">
          <p className="text-4xl">{selectedEmoji}</p>
          <p className="text-sm text-muted-foreground mt-2">
            Selected emoji
          </p>
        </div>
      )}
    </div>
  );
}

Custom Columns

Adjust the number of emoji columns:
import {
  EmojiPicker,
  EmojiPickerContent,
  EmojiPickerSearch,
} from "@/components/ui/emoji-picker";

export default function EmojiPickerCustomColumns() {
  return (
    <EmojiPicker
      columns={10}
      onEmojiSelect={({ emoji }) => console.log(emoji)}
    >
      <EmojiPickerSearch />
      <EmojiPickerContent />
    </EmojiPicker>
  );
}
Show active emoji info and skin tone selector in footer:
import {
  EmojiPicker,
  EmojiPickerContent,
  EmojiPickerFooter,
  EmojiPickerSearch,
  EmojiPickerSkinToneSelector,
} from "@/components/ui/emoji-picker";

export default function EmojiPickerWithFooter() {
  return (
    <EmojiPicker onEmojiSelect={({ emoji }) => console.log(emoji)}>
      <EmojiPickerSearch placeholder="Search..." />
      <EmojiPickerContent />
      <EmojiPickerFooter>
        <EmojiPickerSkinToneSelector emoji="👋" />
      </EmojiPickerFooter>
    </EmojiPicker>
  );
}

In a Form

Use the emoji picker as part of a form:
import { useState } from "react";
import { Button } from "@/components/ui/button";
import {
  EmojiPicker,
  EmojiPickerContent,
  EmojiPickerSearch,
} from "@/components/ui/emoji-picker";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";

export default function EmojiPickerInForm() {
  const [emoji, setEmoji] = useState("😀");
  const [name, setName] = useState("");

  return (
    <form className="space-y-4">
      <div className="space-y-2">
        <Label htmlFor="name">Project Name</Label>
        <Input
          id="name"
          value={name}
          onChange={(e) => setName(e.target.value)}
          placeholder="My awesome project"
        />
      </div>
      <div className="space-y-2">
        <Label>Project Icon</Label>
        <div className="flex gap-2">
          <div className="flex h-10 w-10 items-center justify-center rounded-md border text-2xl">
            {emoji}
          </div>
          <Popover>
            <PopoverTrigger render={<Button variant="outline">Change</Button>} />
            <PopoverContent className="w-fit p-0">
              <EmojiPicker onEmojiSelect={({ emoji }) => setEmoji(emoji)}>
                <EmojiPickerSearch />
                <EmojiPickerContent />
              </EmojiPicker>
            </PopoverContent>
          </Popover>
        </div>
      </div>
      <Button type="submit">Create Project</Button>
    </form>
  );
}

Features

  • Search: Filter emojis by name or keyword
  • Categories: Emojis organized by category (smileys, animals, food, etc.)
  • Skin Tones: Support for skin tone variants on applicable emojis
  • Keyboard Navigation: Full keyboard support for accessibility
  • Loading States: Built-in loading and empty states
  • Responsive: Adapts to different screen sizes
  • Customizable: Adjust columns, styling, and behavior

Accessibility

  • Keyboard navigation with arrow keys
  • Screen reader support for emoji labels
  • Focus management for search input
  • Proper ARIA attributes
  • High contrast support

About Frimousse

The Emoji Picker is built using Frimousse, an unstyled emoji picker library by Liveblocks. Frimousse provides:
  • Comprehensive emoji dataset
  • Virtual scrolling for performance
  • Skin tone management
  • Search functionality
  • Flexible component architecture
For more advanced usage and API details, see the Frimousse documentation.

Build docs developers (and LLMs) love