Skip to content
HyperDesign System

Select

Pick one value from a short list. A pill trigger opens the brand popover menu; keyboard, typeahead and focus return come from Radix. Source: src/components/ui/select.tsx.

Default

Label it with htmlFor pointing at the trigger's id. Controlled with value and onValueChange; the note below follows the choice.

The default for most agents

Variants

Outline for a sort or setting on the canvas; tint for a toolbar, next to tint Buttons. Both lift to tint on hover and while open.

variant="outline"
variant="tint"

Sizes

Two heights, on the Button scale, so a select lines up with the buttons beside it.

sm · 32
default · 36

Groups, placeholder and validation

Group long lists under labels. A placeholder means nothing is chosen yet. Submit without choosing to see the error.

Where run data is stored.

Known gap: the trigger has no aria-invalid style, unlike Input. The attribute is still announced to screen readers, but the error is carried by the message alone. There is no Field primitive to wire the two.

Disabled

Disable the whole select on the root, or single items with disabled on SelectItem.

disabled · outline
disabled · tint

Props

Select props
PropTypeDefaultDescription
SelectRadix Select.Root props—value / defaultValue, onValueChange, open / onOpenChange, disabled, required, name (for native form posts).
SelectTrigger variant"outline" | "tint""outline"outline is the Button outline look; tint is the toolbar pill. Mirrored as data-variant.
SelectTrigger size"sm" | "default""default"32px or 36px, matching Button sm and default. Set via data-size, not cva.
SelectValue placeholderReactNode—Shown, on the third text tier, until a value is chosen.
SelectContentRadix Select.Content propsposition="popper", sideOffset={4}The menu: 14px corners, glass shadow, at least as wide as the trigger. Enter 140ms, exit 90ms.
SelectItemRadix Select.Item props—value is required; disabled dims it and skips it in keyboard navigation. The selected item shows an accent check.
SelectGroup / SelectLabel / SelectSeparatorRadix props—Group related items under a non-selectable label; a hairline separates groups.

Best practices

When to use

  • One choice from roughly 3 to 15 options.
  • Two or three options that should all stay visible: a Toggle group.
  • A long or searchable list needs a combobox (Command in a Popover); there is no Combobox primitive yet.
  • Choosing an action, not a value: a Dropdown menu.

Behavior

  • Give the trigger a fixed width (w-48) when values differ in length, so the layout doesn't jump on change.
  • Default to the most common value rather than a placeholder when one is safe.
  • The menu opens below as a popover; it never covers the trigger.

Accessibility

  • Label it: Label htmlFor the trigger id, or aria-label on the trigger in a toolbar.
  • Arrow keys move, typing jumps to a match, Enter selects, Escape closes and returns focus.
  • Link helper and error text with aria-describedby on the trigger.

Content

  • Options are short and parallel: Most recent, Oldest, Name. Explain the effect below the field, not in the option.