Primitives
Emoji Icon Picker
BetaBeta — the props contract is close to final, but small breaking changes can still land.Emoji and icon selection in one popover with an animated height between panels.
Composition
Emoji or icon
Place inside PopoverContent. Each panel owns its selection callback; the host stores the selected symbol and closes the popover.
- <EmojiIconPicker>
- <EmojiIconPickerTabs />
- <EmojiIconPickerEmoji>
- <EmojiPickerSearch />
- <EmojiPickerContent />
- <EmojiIconPickerIcons>
- <IconPickerSearch />
- <IconPickerContent />
Installation
First install and activate one skin. Core deliberately contains no visual token defaults.
The Control UI source installs this primitive from src/registry/sources/control-ui/ui/emoji-icon-picker.tsx.
npx shadcn@latest add https://control-ui.dev/r/emoji-icon-picker.jsonDependencies
Raw code
Primary installed source
"use client";import type { ComponentProps } from "react";import { EmojiPicker } from "@/components/control-ui/ui/emoji-picker";import { IconPicker } from "@/components/control-ui/ui/icon-picker";import { PopoverViewport } from "@/components/control-ui/ui/popover";import { Tabs, TabsList, TabsPanel, TabsTab } from "@/components/control-ui/ui/tabs";export function EmojiIconPicker({ children, defaultValue = "emoji", ...props }: ComponentProps<typeof Tabs<"emoji" | "icons">>) { return ( <Tabs data-control-ui="emoji-icon-picker" data-control-family="tabs" data-slot="root" defaultValue={defaultValue} {...props}> <PopoverViewport>{children}</PopoverViewport> </Tabs> );}export function EmojiIconPickerTabs({ emojiLabel = "Emoji", iconsLabel = "Icons", ...props}: Omit<ComponentProps<typeof TabsList>, "children"> & { emojiLabel?: string; iconsLabel?: string }) { return ( <TabsList size="xs" className="mx-2 mt-2" aria-label="Choose emoji or icon" {...props}> <TabsTab value="emoji">{emojiLabel}</TabsTab> <TabsTab value="icons">{iconsLabel}</TabsTab> </TabsList> );}export function EmojiIconPickerEmoji(props: ComponentProps<typeof EmojiPicker>) { return ( <TabsPanel value="emoji" data-slide={undefined} className="mt-0"> <EmojiPicker {...props} /> </TabsPanel> );}export function EmojiIconPickerIcons(props: ComponentProps<typeof IconPicker>) { return ( <TabsPanel value="icons" data-slide={undefined} className="mt-0"> <IconPicker {...props} /> </TabsPanel> );}Knobs
Typed custom properties the recipe paints with. Set one on the root — style, a utility class, or a skin — and every slot inherits it.
--cui-tabs-* · 13 knobsHow the cascade resolves--cui-tabs-trigger-radius<length-percentage>var(--radius-control)--cui-tabs-list-padding<length-percentage>calc(var(--spacing) * 1)--cui-tabs-list-radius<length-percentage>calc(
var(--cui-tabs-trigger-radius) +
clamp(0px, calc(var(--cui-tabs-trigger-radius) * 1000), var(--cui-tabs-list-padding))
)--cui-tabs-list-background<color>var(--hover-fill)--cui-tabs-list-backdrop-filter*none--cui-tabs-indicator-background*var(--background)--cui-tabs-foreground<color>var(--muted-foreground)--cui-tabs-active-foreground<color>var(--foreground)--cui-tabs-hover-foreground<color>var(--foreground)--cui-tabs-indicator-shadow*var(--shadow-sm)--cui-tabs-list-shadow*inset 0 0 0 var(--control-rim-width) var(--control-rim), var(--shadow-inset)--cui-tabs-border-color<color>var(--border)--cui-tabs-border-width<length>var(--control-rim-width)