components / form
Select
Pick an option from a list that opens from the button.
select-default.tsx
import { Field, FieldLabel } from "@/components/ui/field";
import { Select, SelectItem, SelectPopup, SelectTrigger, SelectValue } from "@/components/ui/select";
const frameworks = [
{ value: "next", label: "Next.js" },
{ value: "astro", label: "Astro" },
{ value: "remix", label: "React Router" },
{ value: "vite", label: "Vite" },
];
export default function SelectDefault() {
return (
<Field className="w-full max-w-xs">
<FieldLabel>framework</FieldLabel>
<Select defaultValue="next" items={frameworks}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectPopup>
{frameworks.map((f) => (
<SelectItem key={f.value} value={f.value}>
{f.label}
</SelectItem>
))}
</SelectPopup>
</Select>
</Field>
);
}Installation
$ npx shadcn@latest add https://cd-ui.vercel.app/r/select.jsonfirst time? set up components.json and the theme first: see installation.
Usage
import { Select, SelectItem, SelectPopup, SelectTrigger, SelectValue } from "@/components/ui/select"
<Select items={items} defaultValue="next">
<SelectTrigger><SelectValue /></SelectTrigger>
<SelectPopup>
{items.map((i) => <SelectItem key={i.value} value={i.value}>{i.label}</SelectItem>)}
</SelectPopup>
</Select>Examples
Groups and a long list
SelectGroup, SelectGroupLabel, and SelectSeparator organize the options. When the list is taller than the screen, it scrolls and arrows appear at the edges.
select-grouped.tsx
import { Field, FieldLabel } from "@/components/ui/field";
import { Select, SelectGroup, SelectGroupLabel, SelectItem, SelectPopup, SelectSeparator, SelectTrigger, SelectValue } from "@/components/ui/select";
const groups = [
{
label: "Americas",
zones: [
{ value: "america/sao_paulo", label: "Sao Paulo (GMT-3)" },
{ value: "america/new_york", label: "New York (GMT-5)" },
{ value: "america/chicago", label: "Chicago (GMT-6)" },
{ value: "america/denver", label: "Denver (GMT-7)" },
{ value: "america/los_angeles", label: "Los Angeles (GMT-8)" },
],
},
{
label: "Europe",
zones: [
{ value: "europe/london", label: "London (GMT+0)" },
{ value: "europe/paris", label: "Paris (GMT+1)" },
{ value: "europe/berlin", label: "Berlin (GMT+1)" },
{ value: "europe/athens", label: "Athens (GMT+2)" },
{ value: "europe/moscow", label: "Moscow (GMT+3)" },
],
},
{
label: "Asia and Pacific",
zones: [
{ value: "asia/dubai", label: "Dubai (GMT+4)" },
{ value: "asia/kolkata", label: "Kolkata (GMT+5:30)" },
{ value: "asia/singapore", label: "Singapore (GMT+8)" },
{ value: "asia/tokyo", label: "Tokyo (GMT+9)" },
{ value: "australia/sydney", label: "Sydney (GMT+10)" },
{ value: "pacific/auckland", label: "Auckland (GMT+12)" },
],
},
];
const items = groups.flatMap((g) => g.zones);
export default function SelectGrouped() {
return (
<Field className="w-full max-w-xs">
<FieldLabel>time zone</FieldLabel>
<Select defaultValue="europe/london" items={items}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectPopup>
{groups.map((group, i) => (
<SelectGroup key={group.label}>
{i > 0 && <SelectSeparator />}
<SelectGroupLabel>{group.label}</SelectGroupLabel>
{group.zones.map((zone) => (
<SelectItem key={zone.value} value={zone.value}>
{zone.label}
</SelectItem>
))}
</SelectGroup>
))}
</SelectPopup>
</Select>
</Field>
);
}API
Select
Base UI · Select.RootRoot. Pass items so the displayed value uses the right label before the list opens.
| prop | type | default |
|---|---|---|
itemsList of options (used by | { value, label }[] | - |
value · defaultValueControlled or initial value. | string | - |
onValueChangeCalled when an option is chosen. | (value) => void | - |
nameTo submit in a form. | string | - |
SelectTrigger · SelectValue
Base UI · Select.Trigger · Select.ValueButton that opens the list and the text of the current value.
| prop | type | default |
|---|---|---|
classNameExtra classes, merged with | string | - |
SelectPopup
Base UI · Select.PopupList. Opens below the trigger in 160ms, closes in 120ms, and scrolls with arrows when it is long.
| prop | type | default |
|---|---|---|
alignItemWithTriggerPuts the chosen item over the trigger, as on macOS. Off by default: the list doesn't jump over the button. | boolean | false |
classNameExtra classes, merged with | string | - |
SelectGroup · SelectGroupLabel · SelectSeparator
Base UI · Select.Group · Select.GroupLabel · Select.SeparatorSelectGroup groups options, SelectGroupLabel names the group, and SelectSeparator draws a line between groups.
| prop | type | default |
|---|---|---|
classNameExtra classes, merged with | string | - |
SelectItem
Base UI · Select.ItemOption with a yellow check on the right when chosen.
| prop | type | default |
|---|---|---|
valueOption value. | string | - |
classNameExtra classes, merged with | string | - |
Keyboard
| key | action |
|---|---|
| SpaceEnter↓ | Opens the list. |
| ↑↓ | Moves between options. |
| Enter | Chooses the option. |
| Esc | Closes without changing. |
| A-Z | Jumps to the option that starts with the letter. |