Select
Pick one value from a list. By default the list opens with the selected option over the trigger.
WAI-ARIA patternInstallation
npx nuecrea-ui add selectUsage
import * as Select from '@/components/ui/select';
function Option({ value, label, disabled }: { value: string; label: string; disabled?: boolean }) {
return (
<Select.Item value={value} disabled={disabled}>
<Select.ItemText>{label}</Select.ItemText>
<Select.ItemIndicator />
</Select.Item>
);
}
const frameworks = {
react: 'React',
angular: 'Angular',
vue: 'Vue',
svelte: 'Svelte',
solid: 'Solid',
};
const sizes = { sm: 'Small', md: 'Medium', lg: 'Large' };
export default function SelectStory() {
return (
<main className="grid gap-8">
<Select.Root name="framework" required items={frameworks}>
<div className="grid gap-1.5">
<Select.Label>Framework</Select.Label>
<Select.Trigger>
<Select.Value placeholder="Choose a framework" />
<Select.Icon />
</Select.Trigger>
</div>
<Select.Portal>
<Select.Positioner>
<Select.Popup>
<Select.List>
<Select.Group>
<Select.GroupLabel>Popular</Select.GroupLabel>
<Option value="react" label="React" />
<Option value="angular" label="Angular" />
<Option value="vue" label="Vue" disabled />
</Select.Group>
<Select.Separator />
<Select.Group>
<Select.GroupLabel>Others</Select.GroupLabel>
<Option value="svelte" label="Svelte" />
<Option value="solid" label="Solid" />
</Select.Group>
</Select.List>
</Select.Popup>
</Select.Positioner>
</Select.Portal>
</Select.Root>
<Select.Root defaultValue="md" items={sizes}>
<div className="grid gap-1.5">
<Select.Label>Size</Select.Label>
<Select.Trigger>
<Select.Value />
<Select.Icon />
</Select.Trigger>
</div>
<Select.Portal>
<Select.Positioner>
<Select.Popup>
<Select.List>
<Option value="sm" label="Small" />
<Option value="md" label="Medium" />
<Option value="lg" label="Large" />
</Select.List>
</Select.Popup>
</Select.Positioner>
</Select.Portal>
</Select.Root>
<Select.Root disabled defaultValue="eu" items={{ eu: 'Europe' }}>
<div className="grid gap-1.5">
<Select.Label>Region</Select.Label>
<Select.Trigger>
<Select.Value />
<Select.Icon />
</Select.Trigger>
</div>
<Select.Portal>
<Select.Positioner>
<Select.Popup>
<Select.List>
<Option value="eu" label="Europe" />
</Select.List>
</Select.Popup>
</Select.Positioner>
</Select.Portal>
</Select.Root>
</main>
);
}API reference
Select.Root
Owns value and open state; submits through a hidden input. Renders nothing.
| Prop | Type | Default | Description |
|---|---|---|---|
value | unknown | — | Controlled value. |
defaultValue | unknown | — | Initial value. |
items | Record<string, string> | { label: string; value: unknown }[] | — | Labels for values, so the trigger can show a label before the list has opened. |
name | string | — | Form field name of the hidden input. |
disabled | boolean | false | Disabled. |
readOnly | boolean | false | Can't change (aria-readonly, data-readonly). |
required | boolean | false | Required (aria-required). |
modal | boolean | true | Lock page scroll while open. |
| Event | Payload | Description |
|---|---|---|
onValueChange | unknown | Angular: the `value` model's change event; also a ControlValueAccessor. |
onOpenChange | boolean | Angular: the `open` model's change event. |
Select.Label
Labels the trigger. Renders <div>.
Select.Trigger
role=combobox. Arrows/Enter/Space open; typing selects without opening. Renders <button> with role combobox.
| Data attribute | Present when |
|---|---|
data-popup-open | open |
data-popup-side | open: the side (bottom while aligned) |
data-pressed | opened by pointer |
data-disabled | disabled |
data-placeholder | no value |
Select.Value
The selected label, or the placeholder. Renders <span>.
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder | string | — | Shown with no value. |
| Data attribute | Present when |
|---|---|
data-placeholder | no value |
Select.Icon
Decorative (styled: up/down chevrons). Renders <span>.
| Data attribute | Present when |
|---|---|
data-popup-open | open |
Select.Portal
Moves the list to the end of <body>; stays mounted after first open. Renders <div>.
Select.Positioner
Positions the list; alignItemWithTrigger (default) puts the selected option over the trigger, falling back to anchoring near viewport edges. Renders <div> with role presentation.
| Prop | Type | Default | Description |
|---|---|---|---|
alignItemWithTrigger | boolean | true | Align the selected option with the trigger. |
| Data attribute | Present when |
|---|---|
data-open | open |
data-closed | closed (the popup stays mounted after first open) |
data-align | resolved alignment |
data-side | 'none' while aligned with the trigger, else the resolved side |
Select.Popup
The list container. Renders <div> with role presentation.
| Data attribute | Present when |
|---|---|
data-open | open |
data-closed | closed (the popup stays mounted after first open) |
data-align | resolved alignment |
data-side | 'none' while aligned with the trigger, else the resolved side |
data-starting-style | animating in |
data-ending-style | animating out |
Select.List
role=listbox. Renders <div> with role listbox.
Select.Item
An option; disabled options are focusable but not selectable. Renders <div> with role option.
| Prop | Type | Default | Description |
|---|---|---|---|
value | unknown | — | The option's value. |
disabled | boolean | false | Not selectable. |
| Data attribute | Present when |
|---|---|
data-selected | selected |
data-highlighted | highlighted |
data-disabled | disabled |
Select.ItemText
The option's label; aligned over the trigger's value. Renders <div>.
Select.ItemIndicator
Shown on the selected option (styled: a check). Renders <span>.
| Data attribute | Present when |
|---|---|
data-selected | selected |
Select.Group
Groups options. Renders <div> with role group.
Select.GroupLabel
Labels a group. Renders <div>.
Select.Separator
A divider (presentational). Renders <div> with role presentation.
| Data attribute | Present when |
|---|---|
data-orientation | always: horizontal |
Keyboard
| Key | Action |
|---|---|
| ArrowDown / ArrowUp / Enter / Space | On the trigger: open on the selected option. |
| Letters | On the closed trigger: select the next matching option (no wrap). Open: highlight it. |
| ArrowDown / ArrowUp | Move (no wrap); disabled options included. |
| Home / End | First / last option. |
| Enter / Space | Select and close. |
| Escape / Tab | Close; focus returns to the trigger. |