Select

Use the select component to let users choose an option from a long list. For shorter lists (fewer than 7 options), consider using radios instead.

Default Select (Radix UI)

Built with Radix UI primitives for full accessibility and consistent styling across all browsers. The dropdown is fully customisable with CSS.

import * as Select from '@radix-ui/react-select';
import { ChevronDown, Check } from 'lucide-react';

<div className="form-group">
  <label className="form-label">Sort by</label>
  <Select.Root>
    <Select.Trigger className="radix-select-trigger">
      <Select.Value placeholder="Select an option" />
      <Select.Icon className="radix-select-icon">
        <ChevronDown size={20} />
      </Select.Icon>
    </Select.Trigger>
    <Select.Portal>
      <Select.Content className="radix-select-content" position="popper" sideOffset={4}>
        <Select.Viewport className="radix-select-viewport">
          <Select.Item className="radix-select-item" value="published">
            <Select.ItemText>Recently published</Select.ItemText>
            <Select.ItemIndicator className="radix-select-item-indicator">
              <Check size={16} />
            </Select.ItemIndicator>
          </Select.Item>
          ...
        </Select.Viewport>
      </Select.Content>
    </Select.Portal>
  </Select.Root>
</div>

With Hint Text

Select the county where you currently reside.
<div className="form-group">
  <label className="form-label">Where do you live?</label>
  <Select.Root>
    <Select.Trigger className="radix-select-trigger">
      <Select.Value placeholder="Select a county" />
      ...
    </Select.Trigger>
    ...
  </Select.Root>
  <span className="form-hint">Select the county where you currently reside.</span>
</div>

With Option Groups

Use Select.Group and Select.Label to group related options.

<Select.Viewport className="radix-select-viewport">
  <Select.Group>
    <Select.Label className="radix-select-label">Government</Select.Label>
    <Select.Item className="radix-select-item" value="cabinet">
      <Select.ItemText>Cabinet Office</Select.ItemText>
      ...
    </Select.Item>
    ...
  </Select.Group>
  <Select.Separator className="radix-select-separator" />
  <Select.Group>
    <Select.Label className="radix-select-label">Services</Select.Label>
    ...
  </Select.Group>
</Select.Viewport>

Pre-selected Value

Use defaultValue to set an initial selection.

<Select.Root defaultValue="kah">
  <Select.Trigger className="radix-select-trigger">
    <Select.Value />
    ...
  </Select.Trigger>
  ...
</Select.Root>

Error State

Select a county
<div className="form-group form-group-error">
  <label className="form-label">Where do you live?</label>
  <span className="form-error-message">Select a county</span>
  <Select.Root>
    <Select.Trigger className="radix-select-trigger">
      ...
    </Select.Trigger>
    ...
  </Select.Root>
</div>

Disabled State

<Select.Root disabled>
  <Select.Trigger className="radix-select-trigger">
    <Select.Value placeholder="Cannot be changed" />
    ...
  </Select.Trigger>
  ...
</Select.Root>

Controlled Select

Use controlled components when you need to manage state in React.

const [value, setValue] = useState('');

<Select.Root value={value} onValueChange={setValue}>
  <Select.Trigger className="radix-select-trigger">
    <Select.Value placeholder="Select an option" />
    ...
  </Select.Trigger>
  ...
</Select.Root>

When to Use Select

Use select when:

  • There are more than 6-7 options
  • The list of options is familiar to users (e.g., countries, months)
  • Screen space is limited

Consider alternatives when:

  • There are fewer than 7 options — use radios
  • Users can select multiple options — use checkboxes
  • Users might need to enter a value not in the list — use text input with autocomplete

Accessibility

  • Built with Radix UI primitives for full WAI-ARIA compliance
  • Always include a label associated with the select trigger
  • Use placeholder for the initial prompt
  • Full keyboard navigation: Arrow keys to navigate, Enter to select, Escape to close
  • Clear focus states with yellow outline
  • Screen reader announces selected value and available options

CSS Classes

/* Radix select trigger (visible button) */
.radix-select-trigger { }
.radix-select-icon { }

/* Dropdown content */
.radix-select-content { }
.radix-select-viewport { }

/* Items */
.radix-select-item { }
.radix-select-item-indicator { }

/* Groups */
.radix-select-label { }
.radix-select-separator { }

/* Error state */
.form-group-error { }
.form-error-message { }

Installation

npm install @radix-ui/react-select lucide-react