Skip to content

Select

<Select> is the standard single-choice dropdown — Radix-backed, fully keyboard-accessible. Use it when the option list is static and ≤ ~30 items.

import from "@na/ui/components/select" ▶ Open in Storybook packages/ui/src/components/select.tsx

When to use

  • Country, language, timezone — known finite lists.
  • Form fields where the choice is one of many small enumerations.

Don’t use Select for: searchable / async lists (Combobox — planned), 2–5 visible-at-once choices (SegmentedControl or RadioGroup), or > ~30 options where typing-to-search saves time (also Combobox).

Default

<Select defaultValue="us">
<SelectTrigger>
<SelectValue placeholder="Select a country" />
</SelectTrigger>
<SelectContent>
<SelectItem value="us">United States</SelectItem>
<SelectItem value="ca">Canada</SelectItem>
<SelectItem value="vn">Vietnam</SelectItem>
</SelectContent>
</Select>

With groups

<SelectGroup> + <SelectLabel> adds a non-clickable section header inside the dropdown.

<Select>
<SelectTrigger><SelectValue placeholder="Pick a fruit" /></SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Citrus</SelectLabel>
<SelectItem value="orange">Orange</SelectItem>
<SelectItem value="lemon">Lemon</SelectItem>
</SelectGroup>
<SelectGroup>
<SelectLabel>Berries</SelectLabel>
<SelectItem value="strawberry">Strawberry</SelectItem>
</SelectGroup>
</SelectContent>
</Select>

Disabled

<Select disabled defaultValue="us"></Select>

API

Select (root)

Prop Type Default Description
value string Controlled value. Pair with onValueChange.
defaultValue string Initial value for uncontrolled mode.
onValueChange (value: string) => void Fires on every change.
disabled boolean false Disable the trigger.
name string Form-submission name.

SelectTrigger

Prop Type Default Description
children ReactNode Usually <SelectValue />.
className string Forwarded.

SelectContent

Prop Type Default Description
position "item-aligned" | "popper" "popper" Anchor positioning. popper recommended.
children ReactNode SelectItem / SelectGroup / SelectLabel / SelectSeparator.

SelectItem

Prop Type Default Description
value * string Unique value.
disabled boolean false Skip this item.
children ReactNode Visible label.

Design guidelines

✓ Do

  • Pair with a Label and a SelectValue placeholder. Empty Selects look broken.
  • Group only when groups carry meaning. Two items in two groups is overkill.
  • Sort items by the user's mental model — frequency, alphabetical, or geographic.

✗ Don't

  • Use Select with hundreds of items. Reach for Combobox once typing-to-search would help.
  • Use Select for 3 options where you have horizontal room. SegmentedControl or RadioGroup is faster.
  • Hardcode option lists across files. Pull from a single source of truth (an enum, an API, …).

Accessibility

  • Composes Radix Select — combobox role on the trigger, listbox on the content. Type-ahead via item text. Arrow keys navigate, Enter selects, Esc closes.
  • The trigger is a button; pair with a <Label htmlFor> if outside a form context.
  • Combobox — Searchable / async (planned).
  • SelectRow — Select composed with label + description in a list-row layout.
  • Form — react-hook-form integration with Select.

▶ Open Select stories in Storybook