Select
Displays a list of options for the user to pick one from, opened by a button, with groups, separators and keyboard navigation.
Installation
bash
npx shadcn@latest add @redpanda/selectbash
pnpm dlx shadcn@latest add @redpanda/selectbash
yarn dlx shadcn@latest add @redpanda/selectbash
bunx shadcn@latest add @redpanda/selectbash
nubx shadcn@latest add @redpanda/selectbash
aube dlx shadcn@latest add @redpanda/selectWhen to use
Select components provide single-option selection from a list of options. Use this decision tree:
Usage
tsx
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';tsx
<Select> <SelectTrigger className="w-[180px]"> <SelectValue placeholder="Theme" /> </SelectTrigger> <SelectContent> <SelectItem value="light">Light</SelectItem> <SelectItem value="dark">Dark</SelectItem> <SelectItem value="system">System</SelectItem> </SelectContent></Select>Anatomy
The Select component is built with Base UI primitives:
plaintext
<Select> (Root Container)├── <SelectTrigger> (Button)│ ├── <SelectValue> (Placeholder/Selected)│ └── <ChevronDown> Icon├── <SelectContent> (Dropdown)│ ├── Portal rendering│ ├── Positioning system│ └── <SelectItem> (Options)│ ├── Checkmark indicator│ └── Item text└── Keyboard/Mouse handlingProps
Resolving labels in the trigger
<SelectValue> accepts three forms for the trigger label, in order of preference:
- No children — the registry wrapper defers to Base UI’s native resolution. Pass an
itemsmap on<Select>to look up the label, otherwise the raw value is stringified. - Static children — render the same node regardless of value (rarely useful for selects).
- Render-prop children —
(value) => ReactNode. Returningnull/undefinedfalls back toplaceholder. Use this for rich trigger content (icon + label, avatar + name, status dot + label) that mirrors the selected item.
tsx
<Select items={{ '1': 'Any', '2': 'Read', '3': 'Write' }} value="1"> <SelectTrigger> <SelectValue placeholder="Select operation" /> </SelectTrigger> …</Select>
// or, for rich content:<SelectValue placeholder="Assign to teammate"> {(value) => { const user = users.find((u) => u.value === value); return user ? <UserContent user={user} /> : null; // null → placeholder }}</SelectValue>Examples
Scrollable
Groups
Disabled options
With description
With icon
Status indicator
Avatars
Custom rendering
Object values
Placeholder and clearable
Error state
Loading state
Enum-backed value (label ≠ String(value))
Form
Keyboard interactions
| Key | Action |
|---|---|
Enter / Space / ArrowDown on SelectTrigger |
Opens the listbox and focuses the currently selected item (or the first if none). |
ArrowUp / ArrowDown |
Moves between options. |
Home / End |
Jumps to first / last option. |
Enter |
Selects the focused option and closes the listbox. |
Escape |
Closes without changing selection. |
| Typing a character | Typeahead jumps to the next option whose label starts with that character. |
Accessibility
SelectTriggeris a real button witharia-haspopup="listbox"andaria-expanded; the listbox carriesrole="listbox"and each itemrole="option"witharia-selected.- Provide a visible label via
<Label htmlFor>or wrap the select in a<Field>so the selected value has a programmatic name. onValueChangeis typed(value: string, eventDetails) => void— Base UI’s two-argument signature withvaluenarrowed tostring.- For large option lists (>20), prefer
Comboboxso users can type-ahead-filter. Select’s typeahead only jumps to matching first letters.