---
title: Select
description: "Displays a list of options for the user to pick from, triggered by a button."
---

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

const fruits = [
  { label: 'Apple', value: 'apple' },
  { label: 'Banana', value: 'banana' },
  { label: 'Cherry', value: 'cherry' },
];

export default function SelectDemo() {
  return (
    <Select items={fruits}>
      <SelectTrigger>
        <SelectValue placeholder="Select a fruit" />
      </SelectTrigger>
      <SelectContent>
        {fruits.map(({ label, value }) => (
          <SelectItem key={value} value={value}>
            {label}
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  );
}
```

## Install

```bash
npx shadcn@latest add @madeui/select
```

## Usage

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

## Composition

```tsx
<Select>
  <SelectTrigger>
    <SelectValue />
  </SelectTrigger>
  <SelectContent>
    <SelectItem />
  </SelectContent>
</Select>
```

## Groups

```tsx
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectLabel,
  SelectSeparator,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';

const groups = [
  {
    label: 'Fruits',
    items: [
      { label: 'Apple', value: 'apple' },
      { label: 'Banana', value: 'banana' },
      { label: 'Cherry', value: 'cherry' },
    ],
  },
  {
    label: 'Vegetables',
    items: [
      { label: 'Carrot', value: 'carrot' },
      { label: 'Potato', value: 'potato' },
      { label: 'Onion', value: 'onion' },
    ],
  },
];

const items = groups.flatMap((group) => group.items);

export default function SelectGroups() {
  return (
    <Select items={items}>
      <SelectTrigger>
        <SelectValue placeholder="Select a food" />
      </SelectTrigger>
      <SelectContent>
        {groups.map((group, index) => (
          <SelectGroup key={group.label}>
            {index > 0 && <SelectSeparator />}
            <SelectLabel>{group.label}</SelectLabel>
            {group.items.map(({ label, value }) => (
              <SelectItem key={value} value={value}>
                {label}
              </SelectItem>
            ))}
          </SelectGroup>
        ))}
      </SelectContent>
    </Select>
  );
}
```

## Scrollable

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

const timezones = [
  'UTC-08:00 Pacific', 'UTC-07:00 Mountain', 'UTC-06:00 Central',
  'UTC-05:00 Eastern', 'UTC-03:00 Buenos Aires', 'UTC+00:00 London',
  'UTC+01:00 Paris', 'UTC+02:00 Athens', 'UTC+03:00 Istanbul',
  'UTC+04:00 Dubai', 'UTC+05:30 Mumbai', 'UTC+07:00 Bangkok',
  'UTC+08:00 Singapore', 'UTC+09:00 Tokyo', 'UTC+10:00 Sydney',
  'UTC+12:00 Auckland',
].map((label) => ({ label, value: label }));

export default function SelectScrollable() {
  return (
    <Select items={timezones}>
      <SelectTrigger>
        <SelectValue placeholder="Select a timezone" />
      </SelectTrigger>
      <SelectContent>
        {timezones.map(({ label, value }) => (
          <SelectItem key={value} value={value}>
            {label}
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  );
}
```

## Disabled options

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

const plans = [
  { label: 'Free', value: 'free' },
  { label: 'Pro', value: 'pro' },
  { label: 'Enterprise (contact us)', value: 'enterprise', disabled: true },
];

export default function SelectDisabled() {
  return (
    <Select items={plans} defaultValue="pro">
      <SelectTrigger>
        <SelectValue />
      </SelectTrigger>
      <SelectContent>
        {plans.map(({ label, value, disabled }) => (
          <SelectItem key={value} value={value} disabled={disabled}>
            {label}
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  );
}
```

## Disabled

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

const fruits = [{ label: 'Apple', value: 'apple' }];

export default function SelectComponentDisabled() {
  return (
    <Select items={fruits} disabled>
      <SelectTrigger>
        <SelectValue placeholder="Disabled" />
      </SelectTrigger>
      <SelectContent>
        {fruits.map(({ label, value }) => (
          <SelectItem key={value} value={value}>
            {label}
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  );
}
```

## Invalid

Wrap `Select` in a [`Field`](/docs/components/field) with `invalid` — the error propagates to the trigger automatically (`aria-invalid`/`data-invalid`), while `FieldLabel` and `FieldError` carry the visible error state.

```tsx
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { Field, FieldError, FieldLabel } from '@/components/ui/field';

const plans = [
  { label: 'Free', value: 'free' },
  { label: 'Pro', value: 'pro' },
  { label: 'Enterprise', value: 'enterprise' },
];

export default function SelectInvalid() {
  return (
    <Field invalid>
      <FieldLabel htmlFor="select-invalid-plan">Plan</FieldLabel>
      <Select items={plans}>
        <SelectTrigger id="select-invalid-plan">
          <SelectValue placeholder="Select a plan" />
        </SelectTrigger>
        <SelectContent>
          {plans.map(({ label, value }) => (
            <SelectItem key={value} value={value}>
              {label}
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
      <FieldError>Please select a plan to continue.</FieldError>
    </Field>
  );
}
```

## API reference

Built on [Base UI Select](https://base-ui.com/react/components/select). The tables below cover the props this library adds or changes — every other prop is forwarded to the underlying Base UI part; see the [Base UI Select API reference](https://base-ui.com/react/components/select#api-reference) for the full list.

### Select (Root)

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `{ label: string; value: any }[]` | — | Item list; lets `SelectValue` render the selected label. |
| `value` | `any` | — | Controlled selected value. |
| `defaultValue` | `any` | — |  |
| `onValueChange` | `(value: any) => void` | — |  |
| `disabled` | `boolean` | `false` |  |

### SelectContent

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `alignItemWithTrigger` | `boolean` | `true` | Overlay the popup on the trigger with the selected item's text aligned to it (macOS-style, with scroll arrows). Set `false` for a plain anchored dropdown below the trigger. |
| `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'bottom'` | Anchored mode only. |
| `sideOffset` | `number` | `4` | Distance from the trigger, in px. |
| `align` | `'start' \| 'center' \| 'end'` | `'center'` | Anchored mode only. |
| `alignOffset` | `number` | `0` |  |
| `style` | `StyleXStyles` | — | StyleX styles merged last — always win over the component's own styles. |

### SelectItem

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` *(required)* | `any` | — |  |
| `disabled` | `boolean` | `false` |  |
| `style` | `StyleXStyles` | — | StyleX styles merged last — always win over the component's own styles. |

### Styling

`SelectTrigger`, `SelectLabel`, and `SelectSeparator` accept `style` (`StyleXStyles`, merged last so caller overrides always win) plus all native props of the element they render.

`SelectValue` and `SelectGroup` are Base UI parts re-exported unstyled.
