Select
A Select allows users to choose one option from a list that opens from a button.
When to Use
- to choose one option from a short, fixed list, such as payment terms or a currency
- when an option has more than text, like a currency code next to its name
- as a control joined to an Input in a Button Group, for example a currency before an amount
When Not to Use
- for a list long enough to need a search (use a Combobox)
- to let the browser render the list (use a Native Select)
- for a few options that can all be shown on the page (use a Radio Group or a Segmented Control)
- to offer actions (use a Dropdown Menu)
| Select | Native Select | Combobox | |
|---|---|---|---|
| Purpose | One option from a short list | One option from the browser’s list | An option from a list long enough to search |
| List | A popup below the trigger | The browser’s own | A popup below the input |
| Typing | Moves focus to the next match | Handled by the browser | Filters the list |
| Option Content | Text, icons, and markup | Text | Text, icons, and markup |
| Several Values | multiple, with the labels on one line | No | multiple, with a chip for each value |
| Clear Button | No | No | showClear |
| Sizes | sm, default | sm, default | 32px only |
| Control | A button with role="combobox" | A select element | An input with role="combobox" |
Anatomy
| Element | Usage |
|---|---|
| Value | Required |
| Trigger | Required |
| Caret | Always shown |
| Group label | Optional |
| Popup | Required |
| Item | Required |
| Separator | Optional |
SelectTrigger adds the caret, SelectItem adds a check at the end of the selected option, and SelectContent renders the portal and the popup, so you don’t need to add them. The popup’s padding is set on SelectGroup, so place every item in a group, even when the group has no label.
Sizes
Set size on SelectTrigger.
| Size | Height | Placement |
|---|---|---|
sm | 28px | A dense toolbar with no Input |
default | 32px | Everywhere else |
An Input is 32px tall and has no other size, so use default for a Select next to one. See Sizing for the rule on controls in a row.
sm Select is next to an Input, it is 28px tall and the Input is 32px tall, so their top and bottom edges don’t line up.Behavior
By default, a Select is modal while its list is open: Base UI locks the page’s scroll and prevents clicks from reaching the page. If you want the page to stay interactive, set modal={false} on Select.
Position
By default, the list opens below the trigger and is aligned with its start edge. If the list doesn’t fit there, Base UI moves it to another side. The list is as wide as the trigger, with a minimum width of 144px. To change its position, use side, sideOffset, align, and alignOffset on SelectContent.
If alignItemWithTrigger is set, the list opens over the trigger, with the selected option on top of the value. This is the default in Base UI, and it is off in Summit.
Overflow
By default, the trigger is as wide as its value. If you set a width and the value is longer than the trigger, the value is truncated to one line. If the list is taller than the space available next to the trigger, it scrolls inside the popup. SelectScrollUpButton and SelectScrollDownButton are rendered only when alignItemWithTrigger is set.
Content
| String | Rule | Example | Counterexample |
|---|---|---|---|
| Placeholder | Say what to choose | “Choose payment terms” | “Select…” |
| Option | Sentence case, with no end period | “Due on receipt” | “Due On Receipt” |
Accessibility
Base UI’s Select sets the roles, moves focus into the list, and returns it to the trigger. You provide the name.
Keyboard
| Key | Result |
|---|---|
Tab | Moves focus to the trigger. If the list is open, closes it without choosing and moves focus to the next control. |
Enter, Space, or ArrowDown on the trigger | Opens the list. Focus moves to the selected option, or to the first option if no value is set. |
ArrowUp on the trigger | Opens the list. Focus moves to the selected option, or to the last option if no value is set. |
| A letter on the trigger | Selects the next option that starts with it. The list stays closed. |
ArrowDown, ArrowUp | Moves focus to the next or the previous option, including disabled options. Focus stops at the first and the last option. |
Home, End | Moves focus to the first or the last option |
| A letter in the list | Moves focus to the next option that starts with it |
Enter or Space on an option | Selects it and closes the list. Focus returns to the trigger. A disabled option does nothing. |
Escape | Closes the list without choosing. Focus returns to the trigger. |
Requirements
FieldLabel, connect a Label to the id of SelectTrigger with htmlFor, or set aria-label on SelectTrigger. A placeholder can’t be used as the name because the trigger’s text is its value.Installation
npx shadcn@latest add @summit/selectUsage
To show the label of the selected option in SelectValue, pass the options to items on Select. If items isn’t set, SelectValue shows the raw value.
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
const terms = [
{ value: 'net-15', label: 'Net 15' },
{ value: 'net-30', label: 'Net 30' },
];
<Select items={terms}>
<SelectTrigger aria-label="Payment terms" className="w-48">
<SelectValue placeholder="Choose payment terms" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{terms.map(({ value, label }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>;With Groups
To name a SelectGroup, add a SelectLabel to it. To divide two groups, place a SelectSeparator between them.
<SelectContent>
<SelectGroup>
<SelectLabel>Americas</SelectLabel>
<SelectItem value="USD">US dollar</SelectItem>
<SelectItem value="CAD">Canadian dollar</SelectItem>
</SelectGroup>
<SelectSeparator />
<SelectGroup>
<SelectLabel>Europe</SelectLabel>
<SelectItem value="EUR">Euro</SelectItem>
<SelectItem value="CHF" disabled>
Swiss franc
</SelectItem>
</SelectGroup>
</SelectContent>In a Field
In a Field, the FieldLabel names the Select, and a click on the label opens the list.
import { Field, FieldDescription, FieldLabel } from '@/components/ui/field';
<Field>
<FieldLabel>Payment terms</FieldLabel>
<Select items={terms}>
<SelectTrigger>
<SelectValue placeholder="Choose payment terms" />
</SelectTrigger>
</Select>
<FieldDescription>Applied to new invoices for this client.</FieldDescription>
</Field>;API Reference
The parts accept the props of their matching parts in Base UI’s Select, where SelectContent is Select.Popup and SelectLabel is Select.GroupLabel. See the Base UI Select documentation for items, value, onValueChange, name, multiple, modal, and OffsetFunction.
SelectTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
size | 'sm' | 'default' | 'default' | The height |
SelectContent
| Prop | Type | Default | Description |
|---|---|---|---|
side | 'top' | 'bottom' | 'left' | 'right' | 'inline-start' | 'inline-end' | 'bottom' | The side of the trigger the list opens on |
sideOffset | number | OffsetFunction | 4 | The gap between the trigger and the list, in pixels |
align | 'start' | 'center' | 'end' | 'start' | The edge of the trigger the list is aligned with |
alignOffset | number | OffsetFunction | 0 | A shift along that edge, in pixels |
alignItemWithTrigger | boolean | false | Opens the list over the trigger, with the selected option on top of it |