Source: https://monarchui.dev/components/select/

Components · Forms

# Select

Single-value picker with typeahead and keyboard navigation.

@rookcom/monarch-react

Component

## Status picker

## Usage examples

The example at the top of the page is the only one for this component.

## Purpose

Picks one value from a short, known list. Built on Radix Select, which provides typeahead, arrow-key navigation and screen-reader semantics.

### Use when

- The list is short enough to scan without searching (statuses, priorities, roles).

### Avoid when

- The list is long or needs searching: use Combobox.
- There are two to five options that should all be visible: a segmented control (planned) or radio choices.

## Design principles

- The trigger looks like an Input (`.mn-input`), so forms read as one family.
- Menu items share the `.mn-menu` styles with DropdownMenu and Combobox.

## API reference

```tsx
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue } from '@rookcom/monarch-react';
```

| Export | Kind | Rendering | Root class |
| --- | --- | --- | --- |
| `Select` | component | client | `.mn-input` |
| `SelectContent` | component | client | `.mn-input` |
| `SelectGroup` | component | client | `.mn-input` |
| `SelectItem` | component | client | `.mn-input` |
| `SelectLabel` | component | client | `.mn-input` |
| `SelectSeparator` | component | client | `.mn-input` |
| `SelectTrigger` | component | client | `.mn-input` |
| `SelectValue` | component | client | `.mn-input` |

`Select`, `SelectGroup` and `SelectValue` are the Radix primitives re-exported unchanged.

`SelectTrigger`, `SelectContent`, `SelectItem`, `SelectLabel` and `SelectSeparator` forward their refs to the Radix parts.

`SelectContent` renders in a portal with `position="popper"` and `sideOffset={4}` by default.

Generated from the TypeScript declarations of `packages/react/src/components/forms/select`.

## Properties

### `Select`

Single-value select built on Radix Select: typeahead, arrow-key navigation, and screen-reader semantics come from the primitive. <Select value={v} onValueChange={setV}> <SelectTrigger placeholder="Choose a status" /> <SelectContent> <SelectItem value="open">Open</SelectItem> </SelectContent> </Select>

| Prop | Type | Description |
| --- | --- | --- |
| `children` | `React.ReactNode` |  |
| `disabled` | `boolean` |  |

### `SelectContent`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

### `SelectGroup`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

### `SelectItem`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `disabled` | `boolean` |  |
| `id` | `string` |  |

### `SelectLabel`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

### `SelectSeparator`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

### `SelectTrigger`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `disabled` | `boolean` |  |
| `id` | `string` |  |
| `invalid` | `boolean` |  |
| `placeholder` | `string` |  |
| `size` | `"sm" \| "md" \| "lg"` |  |

### `SelectValue`

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

## Variants

| Prop | Values | Description |
| --- | --- | --- |
| `size (SelectTrigger)` | `'sm'``'md'``'lg'` | Trigger height, matching Input sizes. Default `md`. Exposed as `data-size`. |

## States

| State | Exposed as | Behaviour |
| --- | --- | --- |
| Placeholder | `data-placeholder` | The `placeholder` text shows in the subtle text colour until a value is chosen. |
| Invalid | `aria-invalid="true"` | Danger border, from `invalid` or the surrounding Field. |
| Highlighted item | `data-highlighted` | The item under the pointer or keyboard focus; the selected item shows a check. |

## Interaction behaviour

- Clicking the trigger opens the list; choosing an item closes it and calls `onValueChange`.
- The selected item is marked with a check indicator.

## Keyboard support

This section is incomplete

Keyboard handling comes from Radix Select and is not covered by Monarch tests yet.

Radix Select provides typeahead and arrow-key navigation.

## Accessibility

Role

combobox (trigger) with a listbox of options

Accessible name

A FieldLabel in the surrounding Field, or

aria-label

on SelectTrigger.

- Inside a required Field the trigger gets `aria-required`, not `required` (invalid on a button).
- Inside an invalid Field the trigger gets `aria-invalid`.

## Responsive behaviour

This section is incomplete

No responsive behaviour is defined; the content is positioned by Radix.

## Theme support

- Trigger and menu colours are semantic tokens, so every theme applies automatically.

## Do and don't

### Do

- Give the trigger a label through Field or `aria-label`.

### Don't

- Do not use Select for long lists that need searching; use Combobox.

## Related components

- [Combobox](https://monarchui.dev/components/combobox/): Searchable single-select for long lists.
- [DropdownMenu](https://monarchui.dev/components/dropdown-menu/): Actions rather than a value.
- [Field](https://monarchui.dev/components/form-field/): Label and error wiring.

## Dependencies

| Kind | Depends on |
| --- | --- |
| npm packages | `@radix-ui/react-select``react` |
| Monarch components | [Field](https://monarchui.dev/components/form-field/) |

## Testing coverage

- Trigger inside an invalid required Field gets aria-invalid and aria-required, not required.
- A labelled trigger renders without axe violations.

| Check | Covered |
| --- | --- |
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery; Cross-browser axe: /components/select |

Tests: `packages/react/src/components/forms/select`

## All example code

### Status picker

```tsx
import { Select, SelectContent, SelectItem, SelectTrigger } from '@rookcom/monarch-react';

<Select defaultValue="open">
  <SelectTrigger aria-label="Status" placeholder="Status" style={{ width: '14rem' }} />
  <SelectContent>
    <SelectItem value="open">Open</SelectItem>
    <SelectItem value="pending">Pending</SelectItem>
    <SelectItem value="resolved">Resolved</SelectItem>
  </SelectContent>
</Select>
```
