Skip to content

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

Variant
Size
Value
Field
State
JSX
<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>
  • 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.
  • 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.
DoA select for a known list of six or more options.
Don'tA select for two choices. Use a switch, or a segmented control to show both.
ChainLocked once you submit
  1. 1LabelSays what to choose. Always visible, above the field.
  2. 2TriggerOpens the list. The chevron at its end turns up while the list is open.
  3. 3ValueThe chosen option, or a placeholder until there is one.
  4. 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.

Field
Sort by
Ghost

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.
Small, 32px
Medium, 40px
Large, 48px

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.

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.

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.

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.

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).

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.

Verify a second account to choose

A disabled select is 40% opacity and can’t be opened. Say why next to it.

  • 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.
DoA visible label above, with the placeholder as a prompt.
Don'tThe placeholder as the label. Once something is chosen, nothing says what it is.
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.

  • Every select needs a label. Use Field, or an aria-label on the trigger when a visible text beside it already says what it is, like Sort by.
  • The trigger is a combobox and the list a listbox, so screen readers announce the label and the current value.
  • Field links the helper or error with aria-describedby and sets aria-invalid on 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.
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.

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.

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.
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.

  • An Input is for values people type. A select and an input in one row should be the same size.
  • A Dialog often holds a select, like the token in a withdrawal.