Select
A select lets people choose one option from a list, like a chain, a sort order or an asset class.
How bids are listed on the auction page
<Field label="Sort bids" helper="How bids are listed on the auction page">
<Select defaultValue="newest">
<SelectTrigger>
<SelectValue placeholder="Select a sort" />
</SelectTrigger>
<SelectContent>
<SelectItem value="newest">Newest</SelectItem>
…
</SelectContent>
</Select>
</Field>When to use
Section titled “When to use”- To choose one option from a known list of about 6 to 15 options, like a duration or an action type.
- To sort or filter a list, next to the list it changes.
When not to use
Section titled “When not to use”- For two options, use a switch, or a segmented control when both should stay visible.
- For three to five options that fit on screen, use a segmented control or radio buttons, so people see every choice at once.
- For a long list or one people search, like tokens or wallets, use a combobox.
- For actions, like Edit or Delete, use a menu. A select chooses a value, it doesn’t start anything.
- For a value people type, use an Input.
Anatomy
Section titled “Anatomy”- 1LabelSays what to choose. Always visible, above the field.
- 2TriggerOpens the list. The chevron at its end turns up while the list is open.
- 3ValueThe chosen option, or a placeholder until there is one.
- 4Helper or errorOptionalExtra guidance. An error takes its place.
Wrap a field select in a Field to give it a label, a helper and an error. The field passes its id, description and error state to the trigger, as it does for an input.
The list opens 4px below the trigger and is at least as wide as it. It flips above the trigger when there isn’t room below. Each row is as tall as the trigger, and the selected row shows a green check.
Variants
Section titled “Variants”Open either one to see the list.
- Field is the default, for forms and filters. It looks like an input: a white box with a neutral border.
- Ghost sits inline after a short label, like Sort by, where a boxed field would be too heavy. It has no border, and gets a light fill on hover.
Set the size on Select, so the trigger and its list match.
- Medium (40px) is the default, for forms.
- Small (32px) is for filters, table toolbars and inline sorting, next to small buttons and inputs.
- Large (48px) is for the main choice in a panel.
A select and the inputs or buttons beside it should be the same size.
Options
Section titled “Options”Groups
Section titled “Groups”Open it to see the groups.
Group options under a label when the list has clear kinds, like actions on tokens and actions on the project. Group every option or none, and never make a group of one. A separator sits between groups.
A disabled option stays in the list at 40% opacity. Say why with a description, like Not available yet, so people don’t wonder where it went.
Logos and descriptions
Section titled “Logos and descriptions”Open them to see logos and descriptions in the list.
Put a chain or token logo before the label when people scan for it by sight. The logo shows in the trigger too. A description adds one line under the label, in the list only, for options that need explaining, like order types.
Long and empty lists
Section titled “Long and empty lists”A long list scrolls after six and a half rows. An empty one says why.
The list scrolls after about six and a half rows, so the cut-off row shows there’s more. When there is nothing to choose, show SelectEmpty with the reason, like No wallets connected.
States
Section titled “States”The field doesn’t change on hover. On focus the border turns green with a soft 3px halo, as on an input. While the list is open the border darkens and the chevron turns up. The row under the pointer or keyboard gets a light fill (surface/accent).
Helper and error
Section titled “Helper and error”Locked once you submit
Choose where the venture launches
A helper sits below the field. An error replaces it and turns the border red. Show an error when people try to submit without choosing.
Disabled
Section titled “Disabled”Verify a second account to choose
A disabled select is 40% opacity and can’t be opened. Say why next to it.
Content
Section titled “Content”- Write the label as a noun, in sentence case and without a colon: Chain, Asset class, Sort bids.
- Write the placeholder as Select a [noun], like Select a chain. Use a default value instead when one choice is right for most people.
- Keep options short and in sentence case. Order them logically, like shortest to longest or most used first, and alphabetically only when there is no natural order.
Behaviour
Section titled “Behaviour”| Key | Action |
|---|---|
| Space, Enter, ↓ | Opens the list with focus on the selected option. |
| ↑ ↓ | Moves between options, skipping disabled ones. |
| Home End | Jumps to the first or last option. |
| Typing | Jumps to the option that starts with the typed letters. |
| Enter | Chooses the focused option and closes the list. |
| Esc | Closes the list without changing the value, and returns focus to the trigger. |
Clicking outside closes the list. While it’s open, the page behind doesn’t scroll.
Accessibility
Section titled “Accessibility”- Every select needs a label. Use
Field, or anaria-labelon the trigger when a visible text beside it already says what it is, like Sort by. - The trigger is a
comboboxand the list alistbox, so screen readers announce the label and the current value. Fieldlinks the helper or error witharia-describedbyand setsaria-invalidon an error.- The selected option is announced as selected, so the green check is never the only sign.
- Focus shows a green border and halo on a field, and a 2px ring on ghost. In Windows high contrast mode the field falls back to an outline.
Select
Section titled “Select”| Prop | Type | Default | Notes |
|---|---|---|---|
size |
"sm" | "md" | "lg" |
"md" |
Sets the trigger and its list: 32, 40 or 48px. |
value |
string |
The chosen value, when you control it. Use defaultValue otherwise. |
|
onValueChange |
(value: string) => void |
Called with the new value. | |
disabled |
boolean |
false |
Every other Radix Select.Root prop passes through, like open, onOpenChange and name.
SelectTrigger
Section titled “SelectTrigger”| Prop | Type | Default | Notes |
|---|---|---|---|
variant |
"field" | "ghost" |
"field" |
Field fills its container; ghost fits its value. |
className |
string |
Usually a width, like w-[180px]. |
Put a SelectValue inside, with a placeholder when there is no default.
SelectContent
Section titled “SelectContent”| Prop | Type | Default | Notes |
|---|---|---|---|
align |
"start" | "center" | "end" |
"start" |
Lines the list up with the trigger. |
sideOffset |
number |
4 |
Gap below the trigger, in px. |
position |
"popper" | "item-aligned" |
"popper" |
Item-aligned places the selected option over the trigger, as on macOS. |
container |
HTMLElement |
document.body |
Where the list renders. |
SelectItem
Section titled “SelectItem”| Prop | Type | Default | Notes |
|---|---|---|---|
value |
string |
Required. | |
description |
ReactNode |
One line under the label, in the list only. | |
disabled |
boolean |
false |
Keep it in the list and say why in description. |
SelectGroup, SelectLabel, SelectSeparator and SelectEmpty take no props of their own.