VisorVisor
ComponentsForm

Select

An accessible dropdown select for choosing from a list of options. Built on Radix UI.

Default

Small Size

Disabled

Portal Container

SelectContent portals into document.body by default. A theme scoped to a class on a wrapper never reaches the body, so the open menu would read the page's theme instead. Pass the wrapper as container and the menu mounts inside it, under the scoped theme.

const [themeRoot, setThemeRoot] = React.useState<HTMLDivElement | null>(null);

<div ref={setThemeRoot} className="my-scoped-theme">
  <Select>
    <SelectTrigger>
      <SelectValue placeholder="Pick one" />
    </SelectTrigger>
    <SelectContent container={themeRoot}>
      <SelectItem value="a">Option A</SelectItem>
      <SelectItem value="b">Option B</SelectItem>
    </SelectContent>
  </Select>
</div>

Installation

npx visor add select

This copies two files into your project:

  • components/ui/select/select.tsx — the component
  • components/ui/select/select.module.css — the styles

Usage

import {
  Select, SelectTrigger, SelectValue,
  SelectContent, SelectItem,
} from '@/components/ui/select/select';

<Select>
  <SelectTrigger>
    <SelectValue placeholder="Pick one" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="a">Option A</SelectItem>
    <SelectItem value="b">Option B</SelectItem>
  </SelectContent>
</Select>

API Reference

SelectProps

PropTypeDefaultDescription
valuestring—Controlled value of the selected item.
defaultValuestring—Default selected value for uncontrolled usage.
onValueChange(value: string) => void—Callback when the selected value changes.
disabledbooleanfalseDisables the select.
size'sm' | 'md' | 'lg''md'Size of the select trigger (on SelectTrigger).
position'popper' | 'item-aligned''popper'Positioning mode of the dropdown content (on SelectContent).

Sub-components

ComponentElementPurpose
Select— (Radix Root)Root provider managing open state and value
SelectTrigger<button>Clickable trigger that opens the dropdown
SelectValue<span>Displays the selected value or placeholder text
SelectContent<div> (portal)Dropdown panel containing options. Portals into document.body unless container is set
SelectItem<div>Individual selectable option with check indicator
SelectGroup<div>Groups related options together
SelectLabel<div>Non-interactive label for an option group
SelectSeparator<div>Visual divider between groups or items
SelectScrollUpButton<div>Scroll-up indicator at the top of a long list
SelectScrollDownButton<div>Scroll-down indicator at the bottom of a long list

Accessibility

  • Built on @radix-ui/react-select with full WAI-ARIA combobox semantics
  • Trigger has role="combobox" with aria-expanded and aria-haspopup="listbox"
  • Content renders a role="listbox"; each item has role="option" with aria-selected
  • Always pair SelectTrigger with a <Label> via htmlFor/id for screen reader association
  • Keyboard: Space/Enter opens the dropdown; Arrow keys navigate options; Enter selects; Escape closes

Label Centering

The label is optically centred in any font: its line box is trimmed to the capital-height band, so capitals (not the font's ascent and descent) sit on the box centre, with the box size unchanged. Firefox keeps the previous rendering. Shared spec: docs/label-centering.md.