Selector

A versatile dropdown selector component with support for search, multiple selection modes, and various item variants. Built on Radix UI Popover primitives for accessibility.

Basic Usage

import { Selector } from '@/components/Selector'

<Selector.Root value={value} onValueChange={setValue}>
  <Selector.Trigger asChild>
    <button>Select option...</button>
  </Selector.Trigger>
  <Selector.Content>
    <Selector.Search placeholder="Search..." />
    <Selector.Group>
      <Selector.Item value="design">Design</Selector.Item>
      <Selector.Item value="dev">Development</Selector.Item>
    </Selector.Group>
    <Selector.AddButton>Add new</Selector.AddButton>
  </Selector.Content>
</Selector.Root>

Multi-Select

Enable multi-selection mode with the multiple prop. Use showCheck to display checkmarks on selected items.

Selected: design, development

const [values, setValues] = useState(['design', 'development'])

<Selector.Root multiple showCheck value={values} onValueChange={setValues}>
  <Selector.Trigger asChild>
    <button>{values.length} selected</button>
  </Selector.Trigger>
  <Selector.Content>
    <Selector.Group>
      <Selector.Item value="design">Design</Selector.Item>
      <Selector.Item value="development">Development</Selector.Item>
    </Selector.Group>
  </Selector.Content>
</Selector.Root>

Item Variants

Selector supports six different item variants for various use cases.

Icon Variant

Items with icons for action menus.

<Selector.Item value="user" variant="icon" icon={<UserIcon />}>
  User
</Selector.Item>

User Variant

Items with avatars and secondary text for user selection.

<Selector.Item
  value="user1"
  variant="user"
  avatar={<Avatar />}
  secondaryText="@username"
>
  User Name
</Selector.Item>

Country Variant

Items with flags for country/currency selection.

<Selector.Item value="nok" variant="country" icon={<FlagNO />}>
  Norwegian Krone (NOK)
</Selector.Item>

Phone Variant

Items with flags and country names for phone number input.

<Selector.Item
  value="us"
  variant="phone"
  icon={<FlagUS />}
  secondaryText="United States"
>
  +1
</Selector.Item>

Company Variant

Items with logos for company/workspace selection.

<Selector.Item value="notion" variant="company" icon={<NotionLogo />}>
  Notion HQ
</Selector.Item>

All Variants Overview

Text (Default)

Icon

User

Country

Phone

Company

Without Search

The search input is optional - simply omit Selector.Search for simpler dropdowns.

<Selector.Content>
  <Selector.Group>
    <Selector.Item value="option1">Option 1</Selector.Item>
    <Selector.Item value="option2">Option 2</Selector.Item>
  </Selector.Group>
</Selector.Content>

Disabled

Items can be disabled individually or the entire selector can be disabled.

Entire selector disabled

Individual items disabled

// Disable entire selector
<Selector.Root disabled>...</Selector.Root>

// Disable individual items
<Selector.Item value="logout" disabled>Log out</Selector.Item>

Controlled

Control the selection state and open state externally.

Value: design | Open: No

const [value, setValue] = useState('design')
const [open, setOpen] = useState(false)

<Selector.Root
  value={value}
  onValueChange={setValue}
  open={open}
  onOpenChange={setOpen}
>
  ...
</Selector.Root>

Accessibility

  • Built on Radix UI Popover primitive for robust accessibility
  • Full keyboard support (Tab to navigate, Enter/Space to select, Escape to close)
  • Proper ARIA attributes for screen readers
  • Focus management within the dropdown
  • Search input filters items in real-time

API Reference

Selector.Root Props

PropTypeDefaultDescription
valuestring | string[]-The controlled value
defaultValuestring | string[]-The default value (uncontrolled)
onValueChange(value: string | string[]) => void-Callback when value changes
multiplebooleanfalseEnable multi-selection mode
showCheckbooleanfalseShow checkmarks on selected items
disabledbooleanfalseDisable the selector
openboolean-Controlled open state
defaultOpenbooleanfalseDefault open state
onOpenChange(open: boolean) => void-Callback when open state changes

Selector.Trigger Props

PropTypeDefaultDescription
asChildbooleanfalseRender as child element
classNamestring-Additional CSS classes

Selector.Content Props

PropTypeDefaultDescription
sideOffsetnumber4Distance from trigger
align'start' | 'center' | 'end''start'Alignment relative to trigger
classNamestring-Additional CSS classes

Selector.Search Props

PropTypeDefaultDescription
placeholderstring'Search...'Placeholder text
classNamestring-Additional CSS classes

Selector.Item Props

PropTypeDefaultDescription
valuestringRequiredUnique value for this item
variant'text' | 'icon' | 'user' | 'country' | 'phone' | 'company''text'Item display variant
iconReact.ReactNode-Icon element (for icon, country, phone, company variants)
avatarReact.ReactNode-Avatar element (for user variant)
secondaryTextstring-Secondary text (for user, phone variants)
disabledbooleanfalseDisable this item
forceCheckboolean-Override showCheck for this item
classNamestring-Additional CSS classes

Selector.Group Props

PropTypeDefaultDescription
labelstring-Accessible label for the group
classNamestring-Additional CSS classes

Selector.AddButton Props

PropTypeDefaultDescription
iconReact.ReactNodePlus iconCustom icon
onClick() => void-Click handler
classNamestring-Additional CSS classes