Not affiliated with official shadcn/ui. Visit ui.shadcn.com for official docs.
Unlock this block—Get Pro at 60% offReact Dialog Block Emoji Picker
Emoji picker dialog with categorized grid, search functionality, skin tone selector, frequently used section, and click-to-copy
Looking to implement shadcn/ui blocks?
Join our Discord community for help from other developers.
Express yourself with the perfect emoji. This React emoji picker dialog provides a comprehensive emoji selection interface with category tabs, instant search, skin tone modifier, frequently used section, and one-click copy or insert functionality. Built with shadcn/ui Dialog, Input, Button, Tabs, ScrollArea, and Popover components using Tailwind CSS, users find and select emojis quickly with intuitive organization. Search emojis, browse categories, adjust skin tone—perfect for chat applications, social platforms, content editors, or any Next.js application where emoji support enhances expressive communication.
"use client";import { useState, useMemo } from "react";import { Smile, Search, Clock, Heart, Coffee, Plane, Lightbulb, Flag, Music, Dog, Check, Copy,} from "lucide-react";import { Button } from "@/components/ui/button";import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger,} from "@/components/ui/dialog";import { Input } from "@/components/ui/input";import { Popover, PopoverContent, PopoverTrigger,} from "@/components/ui/popover";import { cn } from "@/lib/utils";type EmojiCategory = "recent" | "smileys" | "people" | "animals" | "food" | "activities" | "travel" | "objects" | "symbols";type Emoji = { emoji: string; name: string; keywords: string[]; skinTones?: boolean;};const skinTones = ["", "🏻", "🏼", "🏽", "🏾", "🏿"];const emojiData: Record<EmojiCategory, Emoji[]> = { recent: [], smileys: [ { emoji: "😀", name: "grinning face", keywords: ["happy", "smile"] }, { emoji: "😃", name: "grinning face with big eyes", keywords: ["happy", "joy"] }, { emoji: "😄", name: "grinning face with smiling eyes", keywords: ["happy", "joy"] }, { emoji: "😁", name: "beaming face", keywords: ["happy", "smile"] }, { emoji: "😅", name: "grinning face with sweat", keywords: ["hot", "happy"] }, { emoji: "😂", name: "face with tears of joy", keywords: ["laugh", "cry"] }, { emoji: "🤣", name: "rolling on floor laughing", keywords: ["laugh", "lol"] }, { emoji: "😊", name: "smiling face with smiling eyes", keywords: ["happy", "blush"] }, { emoji: "😇", name: "smiling face with halo", keywords: ["angel", "innocent"] }, { emoji: "🙂", name: "slightly smiling face", keywords: ["smile"] }, { emoji: "😉", name: "winking face", keywords: ["wink", "flirt"] }, { emoji: "😍", name: "smiling face with heart-eyes", keywords: ["love", "crush"] }, { emoji: "🥰", name: "smiling face with hearts", keywords: ["love", "adore"] }, { emoji: "😘", name: "face blowing a kiss", keywords: ["kiss", "love"] }, { emoji: "😜", name: "winking face with tongue", keywords: ["playful", "joke"] }, { emoji: "🤔", name: "thinking face", keywords: ["think", "hmm"] }, { emoji: "🤨", name: "face with raised eyebrow", keywords: ["suspicious", "skeptic"] }, { emoji: "😐", name: "neutral face", keywords: ["meh", "blank"] }, { emoji: "😑", name: "expressionless face", keywords: ["blank", "meh"] }, { emoji: "😶", name: "face without mouth", keywords: ["silent", "speechless"] }, { emoji: "😏", name: "smirking face", keywords: ["smug", "smirk"] }, { emoji: "😒", name: "unamused face", keywords: ["meh", "unimpressed"] }, { emoji: "🙄", name: "face with rolling eyes", keywords: ["annoyed", "frustrated"] }, { emoji: "😬", name: "grimacing face", keywords: ["awkward", "nervous"] }, { emoji: "😮💨", name: "face exhaling", keywords: ["relieved", "sigh"] }, { emoji: "🤗", name: "hugging face", keywords: ["hug", "care"] }, { emoji: "😢", name: "crying face", keywords: ["sad", "tear"] }, { emoji: "😭", name: "loudly crying face", keywords: ["sad", "cry", "sob"] }, { emoji: "😤", name: "face with steam", keywords: ["angry", "frustrated"] }, { emoji: "😡", name: "pouting face", keywords: ["angry", "rage"] }, ], people: [ { emoji: "👋", name: "waving hand", keywords: ["hello", "bye"], skinTones: true }, { emoji: "👍", name: "thumbs up", keywords: ["yes", "good", "ok"], skinTones: true }, { emoji: "👎", name: "thumbs down", keywords: ["no", "bad"], skinTones: true }, { emoji: "👏", name: "clapping hands", keywords: ["applause", "congrats"], skinTones: true }, { emoji: "🙌", name: "raising hands", keywords: ["hooray", "celebrate"], skinTones: true }, { emoji: "🤝", name: "handshake", keywords: ["deal", "agreement"] }, { emoji: "🙏", name: "folded hands", keywords: ["please", "pray", "thanks"], skinTones: true }, { emoji: "💪", name: "flexed biceps", keywords: ["strong", "muscle"], skinTones: true }, { emoji: "🤞", name: "crossed fingers", keywords: ["luck", "hope"], skinTones: true }, { emoji: "✌️", name: "victory hand", keywords: ["peace", "victory"], skinTones: true }, { emoji: "🤟", name: "love-you gesture", keywords: ["love", "rock"], skinTones: true }, { emoji: "👀", name: "eyes", keywords: ["look", "see"] }, { emoji: "👁️", name: "eye", keywords: ["see", "look"] }, { emoji: "💅", name: "nail polish", keywords: ["beauty", "manicure"], skinTones: true }, { emoji: "🧠", name: "brain", keywords: ["smart", "think"] }, ], animals: [ { emoji: "🐶", name: "dog face", keywords: ["puppy", "pet"] }, { emoji: "🐱", name: "cat face", keywords: ["kitty", "pet"] }, { emoji: "🐭", name: "mouse face", keywords: ["rodent"] }, { emoji: "🐹", name: "hamster", keywords: ["pet", "rodent"] }, { emoji: "🐰", name: "rabbit face", keywords: ["bunny", "pet"] }, { emoji: "🦊", name: "fox", keywords: ["animal"] }, { emoji: "🐻", name: "bear", keywords: ["animal"] }, { emoji: "🐼", name: "panda", keywords: ["animal", "cute"] }, { emoji: "🐨", name: "koala", keywords: ["animal", "cute"] }, { emoji: "🐯", name: "tiger face", keywords: ["animal"] }, { emoji: "🦁", name: "lion", keywords: ["animal", "king"] }, { emoji: "🐮", name: "cow face", keywords: ["animal", "moo"] }, { emoji: "🐷", name: "pig face", keywords: ["animal"] }, { emoji: "🐸", name: "frog", keywords: ["animal"] }, { emoji: "🐵", name: "monkey face", keywords: ["animal"] }, { emoji: "🦋", name: "butterfly", keywords: ["insect", "beautiful"] }, { emoji: "🐝", name: "honeybee", keywords: ["insect", "bee"] }, { emoji: "🐢", name: "turtle", keywords: ["animal", "slow"] }, { emoji: "🦄", name: "unicorn", keywords: ["magical", "fantasy"] }, ], food: [ { emoji: "🍎", name: "red apple", keywords: ["fruit", "healthy"] }, { emoji: "🍕", name: "pizza", keywords: ["food", "italian"] }, { emoji: "🍔", name: "hamburger", keywords: ["food", "burger"] }, { emoji: "🍟", name: "french fries", keywords: ["food", "fries"] }, { emoji: "🌭", name: "hot dog", keywords: ["food"] }, { emoji: "🍿", name: "popcorn", keywords: ["food", "movie"] }, { emoji: "🍩", name: "doughnut", keywords: ["food", "sweet"] }, { emoji: "🍪", name: "cookie", keywords: ["food", "sweet"] }, { emoji: "🎂", name: "birthday cake", keywords: ["food", "celebration"] }, { emoji: "🍰", name: "shortcake", keywords: ["food", "dessert"] }, { emoji: "☕", name: "hot beverage", keywords: ["coffee", "tea"] }, { emoji: "🍺", name: "beer mug", keywords: ["drink", "alcohol"] }, { emoji: "🍷", name: "wine glass", keywords: ["drink", "alcohol"] }, { emoji: "🥤", name: "cup with straw", keywords: ["drink", "soda"] }, { emoji: "🧁", name: "cupcake", keywords: ["food", "dessert"] }, ], activities: [ { emoji: "⚽", name: "soccer ball", keywords: ["sport", "football"] }, { emoji: "🏀", name: "basketball", keywords: ["sport"] }, { emoji: "🏈", name: "american football", keywords: ["sport"] }, { emoji: "⚾", name: "baseball", keywords: ["sport"] }, { emoji: "🎾", name: "tennis", keywords: ["sport"] }, { emoji: "🎮", name: "video game", keywords: ["gaming", "play"] }, { emoji: "🎯", name: "direct hit", keywords: ["target", "goal"] }, { emoji: "🎪", name: "circus tent", keywords: ["entertainment"] }, { emoji: "🎨", name: "artist palette", keywords: ["art", "paint"] }, { emoji: "🎬", name: "clapper board", keywords: ["movie", "film"] }, { emoji: "🎤", name: "microphone", keywords: ["sing", "karaoke"] }, { emoji: "🎧", name: "headphone", keywords: ["music", "listen"] }, { emoji: "🎹", name: "musical keyboard", keywords: ["music", "piano"] }, { emoji: "🏆", name: "trophy", keywords: ["win", "champion"] }, { emoji: "🥇", name: "1st place medal", keywords: ["win", "gold"] }, ], travel: [ { emoji: "🚗", name: "automobile", keywords: ["car", "drive"] }, { emoji: "✈️", name: "airplane", keywords: ["travel", "fly"] }, { emoji: "🚀", name: "rocket", keywords: ["space", "launch"] }, { emoji: "🚢", name: "ship", keywords: ["boat", "travel"] }, { emoji: "🏠", name: "house", keywords: ["home", "building"] }, { emoji: "🏢", name: "office building", keywords: ["work", "building"] }, { emoji: "🏖️", name: "beach with umbrella", keywords: ["vacation", "summer"] }, { emoji: "🏔️", name: "snow-capped mountain", keywords: ["nature", "hiking"] }, { emoji: "⛰️", name: "mountain", keywords: ["nature", "hiking"] }, { emoji: "🌋", name: "volcano", keywords: ["nature", "eruption"] }, { emoji: "🗽", name: "statue of liberty", keywords: ["new york", "usa"] }, { emoji: "🗼", name: "tokyo tower", keywords: ["japan", "landmark"] }, { emoji: "🌍", name: "globe europe-africa", keywords: ["world", "earth"] }, { emoji: "🌎", name: "globe americas", keywords: ["world", "earth"] }, { emoji: "🌏", name: "globe asia-australia", keywords: ["world", "earth"] }, ], objects: [ { emoji: "💡", name: "light bulb", keywords: ["idea", "light"] }, { emoji: "📱", name: "mobile phone", keywords: ["phone", "cell"] }, { emoji: "💻", name: "laptop", keywords: ["computer", "work"] }, { emoji: "⌨️", name: "keyboard", keywords: ["type", "computer"] }, { emoji: "📷", name: "camera", keywords: ["photo", "picture"] }, { emoji: "📚", name: "books", keywords: ["read", "study"] }, { emoji: "📝", name: "memo", keywords: ["note", "write"] }, { emoji: "📧", name: "e-mail", keywords: ["email", "message"] }, { emoji: "📦", name: "package", keywords: ["box", "delivery"] }, { emoji: "🔑", name: "key", keywords: ["lock", "security"] }, { emoji: "🔒", name: "locked", keywords: ["security", "private"] }, { emoji: "💰", name: "money bag", keywords: ["rich", "wealth"] }, { emoji: "💎", name: "gem stone", keywords: ["diamond", "precious"] }, { emoji: "⏰", name: "alarm clock", keywords: ["time", "wake"] }, { emoji: "🎁", name: "wrapped gift", keywords: ["present", "birthday"] }, ], symbols: [ { emoji: "❤️", name: "red heart", keywords: ["love"] }, { emoji: "🧡", name: "orange heart", keywords: ["love"] }, { emoji: "💛", name: "yellow heart", keywords: ["love"] }, { emoji: "💚", name: "green heart", keywords: ["love"] }, { emoji: "💙", name: "blue heart", keywords: ["love"] }, { emoji: "💜", name: "purple heart", keywords: ["love"] }, { emoji: "🖤", name: "black heart", keywords: ["love"] }, { emoji: "🤍", name: "white heart", keywords: ["love"] }, { emoji: "💔", name: "broken heart", keywords: ["sad", "heartbreak"] }, { emoji: "✨", name: "sparkles", keywords: ["magic", "special"] }, { emoji: "⭐", name: "star", keywords: ["favorite", "rating"] }, { emoji: "🌟", name: "glowing star", keywords: ["bright", "special"] }, { emoji: "💫", name: "dizzy", keywords: ["star", "sparkle"] }, { emoji: "✅", name: "check mark button", keywords: ["yes", "done"] }, { emoji: "❌", name: "cross mark", keywords: ["no", "wrong"] }, { emoji: "❓", name: "question mark", keywords: ["what", "ask"] }, { emoji: "❗", name: "exclamation mark", keywords: ["important", "alert"] }, { emoji: "💯", name: "hundred points", keywords: ["perfect", "score"] }, { emoji: "🔥", name: "fire", keywords: ["hot", "lit"] }, { emoji: "💥", name: "collision", keywords: ["boom", "explosion"] }, ],};const categoryIcons: Record<EmojiCategory, React.ReactNode> = { recent: <Clock className="h-4 w-4" />, smileys: <Smile className="h-4 w-4" />, people: <span className="text-sm">👋</span>, animals: <Dog className="h-4 w-4" />, food: <Coffee className="h-4 w-4" />, activities: <Music className="h-4 w-4" />, travel: <Plane className="h-4 w-4" />, objects: <Lightbulb className="h-4 w-4" />, symbols: <Heart className="h-4 w-4" />,};export const title = "React Dialog Block Emoji Picker";export default function DialogEmojiPicker() { const [open, setOpen] = useState(false); const [search, setSearch] = useState(""); const [category, setCategory] = useState<EmojiCategory>("smileys"); const [skinTone, setSkinTone] = useState(0); const [recentEmojis, setRecentEmojis] = useState<string[]>(["😀", "👍", "❤️", "🔥", "✨", "🎉", "💯", "🙏"]); const [copied, setCopied] = useState<string | null>(null); const filteredEmojis = useMemo(() => { if (!search) { if (category === "recent") { return recentEmojis.map((emoji) => ({ emoji, name: "", keywords: [] })); } return emojiData[category]; } const searchLower = search.toLowerCase(); return Object.values(emojiData) .flat() .filter( (e) => e.name.toLowerCase().includes(searchLower) || e.keywords.some((k) => k.toLowerCase().includes(searchLower)) ); }, [search, category, recentEmojis]); const applySkintone = (emoji: string, hasSkinTones?: boolean) => { if (!hasSkinTones || skinTone === 0) return emoji; return emoji + skinTones[skinTone]; }; const handleSelectEmoji = (emoji: string, hasSkinTones?: boolean) => { const finalEmoji = applySkintone(emoji, hasSkinTones); navigator.clipboard.writeText(finalEmoji); setCopied(finalEmoji); setTimeout(() => setCopied(null), 1000); if (!recentEmojis.includes(emoji)) { setRecentEmojis([emoji, ...recentEmojis.slice(0, 7)]); } }; const handleClose = () => { setOpen(false); setTimeout(() => { setSearch(""); setCopied(null); }, 200); }; const categories: EmojiCategory[] = ["recent", "smileys", "people", "animals", "food", "activities", "travel", "objects", "symbols"]; return ( <Dialog open={open} onOpenChange={setOpen}> <div className="flex min-h-[350px] items-center justify-center"> <DialogTrigger asChild> <Button variant="outline"> <Smile className="mr-2 h-4 w-4" /> Pick Emoji </Button> </DialogTrigger> </div> <DialogContent className="sm:max-w-sm"> <DialogHeader> <DialogTitle className="flex items-center gap-2"> <Smile className="h-5 w-5" /> Emoji Picker </DialogTitle> <DialogDescription> Search or browse emojis. Click to copy. </DialogDescription> </DialogHeader> <div className="space-y-3 py-2"> <div className="flex items-center gap-2"> <div className="relative flex-1"> <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" /> <Input placeholder="Search emojis..." value={search} onChange={(e) => setSearch(e.target.value)} className="pl-9" /> </div> <Popover> <PopoverTrigger asChild> <Button variant="outline" size="icon" className="shrink-0"> <span className="text-lg">👋{skinTone > 0 ? skinTones[skinTone] : ""}</span> </Button> </PopoverTrigger> <PopoverContent className="w-auto p-2" align="end"> <div className="flex gap-1"> {skinTones.map((tone, index) => ( <button key={index} onClick={() => setSkinTone(index)} className={cn( "h-8 w-8 rounded-md flex items-center justify-center text-lg hover:bg-muted transition-colors", skinTone === index && "ring-2 ring-primary" )} > 👋{tone} </button> ))} </div> </PopoverContent> </Popover> </div> {!search && ( <div className="flex gap-1 overflow-x-auto pb-1"> {categories.map((cat) => ( <button key={cat} onClick={() => setCategory(cat)} className={cn( "flex items-center justify-center h-8 w-8 rounded-md transition-colors shrink-0", category === cat ? "bg-primary text-primary-foreground" : "hover:bg-muted" )} title={cat} > {categoryIcons[cat]} </button> ))} </div> )} <div className="h-[200px] overflow-y-auto"> {filteredEmojis.length > 0 ? ( <div className="flex flex-wrap gap-1"> {filteredEmojis.map((item, index) => ( <button key={`${item.emoji}-${index}`} onClick={() => handleSelectEmoji(item.emoji, item.skinTones)} className={cn( "h-8 w-8 rounded-md flex items-center justify-center text-xl hover:bg-muted transition-all hover:scale-110", copied === applySkintone(item.emoji, item.skinTones) && "bg-primary/10" )} title={item.name} > {applySkintone(item.emoji, item.skinTones)} </button> ))} </div> ) : ( <div className="flex flex-col items-center justify-center py-8 text-center"> <Smile className="h-8 w-8 text-muted-foreground mb-2" /> <p className="text-sm font-medium">No emojis found</p> <p className="text-xs text-muted-foreground"> Try a different search term </p> </div> )} </div> {copied && ( <div className="flex items-center justify-center gap-2 text-sm text-primary"> <Check className="h-4 w-4" /> <span>Copied {copied} to clipboard!</span> </div> )} </div> </DialogContent> </Dialog> );}Installation
npx shadcn@latest add https://www.shadcn.io/registry/dialog-emoji-picker.jsonnpx shadcn@latest add https://www.shadcn.io/registry/dialog-emoji-picker.jsonpnpm dlx shadcn@latest add https://www.shadcn.io/registry/dialog-emoji-picker.jsonbunx shadcn@latest add https://www.shadcn.io/registry/dialog-emoji-picker.jsonRelated blocks you will also like
React Dialog Block Quick Reply
Message templates
React Dialog Block Quick Note
Note taking
React Dialog Block Feedback Rating
Reaction feedback
React Dialog Block Color Picker
Visual selection
React Dialog Block Keyboard Shortcuts
Quick access
React Dialog Block Success Confirmation
Copy confirmation