Skip to content
Design System
Contact

Select

Pick one option from a short list, with typeahead and grouped options.

ComponentsRadix Select

Playground

Use a select for one choice from a short, known list. Past about 15 options, or when people need to search, switch to a combobox built on the command palette.

Preview

Valueundefined

Props

Size
Width
Position
example.tsxtsx
1import { Label } from "@/components/ui/label"
2import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue } from "@/components/ui/select"
3
4const [plan, setPlan] = useState("")
5
6<div className="grid gap-1.5">
7 <Label htmlFor="plan">Billing plan</Label>
8 <Select value={plan} onValueChange={setPlan}>
9 <SelectTrigger id="plan" className="w-48">
10 <SelectValue placeholder="Choose a plan" />
11 </SelectTrigger>
12 <SelectContent>
13 <SelectGroup>
14 <SelectLabel>Self-serve</SelectLabel>
15 <SelectItem value="starter">Starter</SelectItem>
16 <SelectItem value="team">Team</SelectItem>
17 <SelectItem value="business">Business</SelectItem>
18 </SelectGroup>
19 <SelectSeparator />
20 <SelectGroup>
21 <SelectLabel>Sales-led</SelectLabel>
22 <SelectItem value="enterprise" disabled>Enterprise</SelectItem>
23 <SelectItem value="custom">Custom contract</SelectItem>
24 </SelectGroup>
25 </SelectContent>
26 </Select>
27</div>

States

States of the trigger. The list itself only has highlighted, selected and disabled items, shown in the playground.

States
  • Defaultrest
  • Hover:hover
  • Focus:focus-visible
  • Loadingaria-busy
  • Disableddisabled
  • Erroraria-invalid
  • Successdata-state=success

Patterns

Rich items keep secondary text in the list and out of the trigger, using the in-data-[slot=select-trigger] variant, so the closed control stays compact.

Deal stage with status dots
Demo data

Northwind platform renewal

Owner Maya Chen, closes Oct 30

ProgressWeighted$24,000 of $48,000
Long list with typeahead

Focus the field and type j a to jump to Japan.

Weekly sync at 15:00 UTC is 16:00 in Berlin.UTC+1, standard time

API

Built on Radix Select. Root props control the value; SelectContent controls placement.

PropTypeDefaultDescription
value / onValueChangestring / (value: string) => void—Controlled value. Use defaultValue for uncontrolled.
disabledbooleanfalseDisables the whole control. Put disabled on SelectItem to lock one option.
SelectTrigger size"sm" | "default""default"28px or 32px height. Width comes from className (w-fit by default).
SelectValue placeholderReactNode—Shown while no value is selected, in muted text.
SelectContent position"item-aligned" | "popper""item-aligned"Item aligned lays the selected item over the trigger like a native select. Popper drops the list below it.
SelectItem textValuestring—Text used for typeahead when the item renders rich content.
SelectGroup / SelectLabel / SelectSeparator——Group related options under a label and divide groups with a hairline.

Accessibility

Keyboard

Open the list
EnterorSpaceor↓
Move between options
↑or↓
First or last option
HomeorEnd
Typeahead to an option
A–Z
Select and close
Enter
Close without changing
Esc

Semantics and ARIA

  • The trigger is a combobox button with aria-expanded and aria-controls; the list is a listbox of options with aria-selected.
  • Name the trigger with <Label htmlFor>. The placeholder is not a name and is not announced once a value is chosen.
  • Typeahead works both open and closed. When items render icons or secondary text, set textValue so typing matches the visible name.
  • Disabled options stay in the list and are skipped by arrow keys, so people can see what exists and why it is locked.
  • A hidden native select mirrors the value, so the control submits with forms and supports autofill.
  • Errors set aria-invalid on the trigger and point aria-describedby at the message.