Select
Picks one value from a short list in a dropdown, as a picklist does.
Installation
The CLI installs the Radix or Base UI file to match your project.
If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.
When to use
Use it
- To pick one value from a short, fixed list, like an opportunity's stage or an account's type: the picklist of record forms.
- For roughly 4 to 15 options, known up front, that don't need searching.
Don't use it
- Two or three options with room to show them. Use Radio group, or Checkbox for yes or no.
- People should type to search a long list, like countries. Use Combobox. To pick a record, like an account, use Lookup.
- People pick several values. Use Checkbox.
- The list holds actions, like Edit or Delete. Use Dropdown menu.
- A plain form post, or the phone's own picker on mobile. Use Native select.
Usage
Select
├── SelectTrigger
│ └── SelectValue
└── SelectContent
├── SelectGroup
│ ├── SelectLabel
│ └── SelectItem
├── SelectSeparator
└── SelectItemTo control the value, pass value and onValueChange:
import { useState } from "react"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
export function PrioritySelect() {
const [priority, setPriority] = useState("Medium")
return (
<Select
value={priority}
onValueChange={(next) => setPriority(next ?? "Medium")}
>
<SelectTrigger aria-label="Priority">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="High">High</SelectItem>
<SelectItem value="Medium">Medium</SelectItem>
<SelectItem value="Low">Low</SelectItem>
</SelectContent>
</Select>
)
}The bases differ in three places:
- In Radix projects,
onValueChangegets the value. In Base UI projects its type allowsnulland it gets event details as a second argument, so the snippet falls back onnull. - In Radix projects, the trigger shows the selected option's text. In Base UI projects it shows the value unless you pass
items, a list of{ value, label }, toSelect. Passitemswhen a value doesn't read as its label, likeneeds-analysis. - To open the list over the field, with the selected option on it, pass
position="item-aligned"toSelectContentin Radix projects, oralignItemWithTriggerin Base UI projects.
Examples
Groups
Options in `SelectGroup`s under `SelectLabel`s, a `SelectSeparator` between them, a `disabled` option and a selected value.
Sizes
The default 32px trigger and the 28px one, set with `size` on `SelectTrigger`, each named by `aria-label` as in a toolbar.
States
A picklist with `aria-invalid` on `SelectTrigger` and an error, and one with `disabled` on `Select`.
Long list
Account's 32 industries: the list shows seven options and scrolls through the rest, as SLDS's picklist does.
API reference
| Part | Built on |
|---|---|
Select | Radix Select.Root (opens in a new tab) |
SelectGroup | Radix Select.Group (opens in a new tab) |
SelectValue | Radix Select.Value (opens in a new tab) |
SelectTrigger | Radix Select.Trigger (opens in a new tab) |
SelectContent | Radix Select.Content (opens in a new tab) |
SelectLabel | Radix Select.Label (opens in a new tab) |
SelectItem | Radix Select.Item (opens in a new tab) |
SelectSeparator | Radix Select.Separator (opens in a new tab) |
SelectScrollUpButton | Radix Select.ScrollUpButton (opens in a new tab) |
SelectScrollDownButton | Radix Select.ScrollDownButton (opens in a new tab) |
SelectTrigger
| Prop | Type | Default |
|---|---|---|
size | "sm" | "default" | "default" |
SelectContent
| Prop | Type | Default |
|---|---|---|
position | "item-aligned" | "popper" | "popper" |
align | "center" | "end" | "start" | "center" |
sideOffset | number | 2 |
SLDS mapping
Select is SLDS's picklist, the read-only combobox (slds-combobox with slds-input_faux), not the native slds-select.
SelectTriggerisslds-input_faux slds-combobox__inputwith its chevron (slds-input__icon_right). It takes the input's border, focus, error and disabled styles.SelectValueis the field'sslds-truncatetext.SelectContentisslds-dropdown slds-dropdown_fluid slds-dropdown_length-with-icon-7.SelectItemisslds-listbox__option slds-listbox__option_plain, with the check inslds-listbox__option-iconon the left.SelectLabelisslds-listbox__option-header, andSelectSeparatoris theslds-has-divider_top-spaceline.
Known gaps:
- No option icons, no option metadata lines, and no five- or ten-row list (
slds-dropdown_length-5,-10).
| Prop | Value | SLDS | Notes |
|---|---|---|---|
SelectTrigger size | default | slds-input_faux slds-combobox__input | 32px, like an input. |
SelectTrigger size | sm | none | SLDS has no small picklist. 28px, like a small button. |
Keyboard interactions
| Keys | Action |
|---|---|
| Enter, Space or Down Arrow | On the trigger, opens the list with the selected option highlighted. |
| Down Arrow, Up Arrow | Moves the highlight to the next or previous option. |
| Home, End | Moves the highlight to the first or last option. |
| Letters | Highlights the next option whose label starts with them. On the closed trigger, selects it. |
| Enter | Selects the highlighted option, closes the list and returns focus to the trigger. |
| Escape | Closes the list without changing the value and returns focus to the trigger. |
Accessibility
- Name the trigger: give it an
idand point aFieldLabel'shtmlForat it, or passaria-label. - For an error, set
aria-invalidonSelectTriggerand pointaria-describedbyat the message. - In Cosmos dark, the error text in an invalid field is about 4.3:1, below WCAG AA's 4.5:1. SLDS's own invalid combobox is the same.
- The highlighted option shows an inset ring on keyboard focus, so the highlight isn't color alone. Keep it if you restyle items.
Motion
- The list appears and disappears at once, with no fade or zoom. If you add animation classes through
className, put them behindmotion-safe:.
Responsive behavior
- The trigger is as wide as its content. Pass
className="w-full"to fill a form column. - The list is at least as wide as the trigger. It shows seven rows, then scrolls, and opens above the field when there's no room below.
- A long label is cut off on one line in the trigger. Keep option labels short.
Rules
- Give every
SelectItema uniquevalue. - Put
SelectValueinsideSelectTrigger, with aplaceholderfor an empty select. - Don't restyle the trigger's border, focus ring or error colors. They come from the input tokens and change per theme.
- Don't put buttons, links or other interactive elements inside
SelectItem.