---
title: Select
description: Displays a native list of options for the user to pick from.
order: 26
tags: [components]
---

import { Preview } from "$lib/components/preview";
import { Select } from "areia";

# Select

Displays a native list of options for the user to pick from.

[Source Code](https://github.com/ilhajs/areia/blob/main/packages/areia/src/components/select/index.ts)

Areia's `Select` uses the platform `<select>` primitive, so it keeps native keyboard, form, and mobile behavior while adding Areia styling and field helpers.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    id="fruit"\n    label="Fruit"\n    value="apple"\n    items={{\n      apple: "Apple",\n      banana: "Banana",\n      cherry: "Cherry",\n    }}\n  />\n));'
  }
  lang="tsx"
>
  <Select
    id="fruit"
    label="Fruit"
    value="apple"
    items={{
      apple: "Apple",
      banana: "Banana",
      cherry: "Cherry",
    }}
  />
</Preview>

## Import

```ts
import { Select } from "areia";
```

## Usage

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    id="plan"\n    label="Plan"\n    placeholder="Choose a plan"\n    items={{\n      free: "Free",\n      pro: "Pro",\n      team: "Team",\n    }}\n  />\n));'
  }
  lang="tsx"
>
  <Select
    id="plan"
    label="Plan"
    placeholder="Choose a plan"
    items={{
      free: "Free",
      pro: "Pro",
      team: "Team",
    }}
  />
</Preview>

## Examples

### Basic

A select with a visible label. When you provide the `label` prop, the select renders with a field wrapper and label above it.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    id="basic-fruit"\n    label="Fruit"\n    value="apple"\n    items={{\n      apple: "Apple",\n      banana: "Banana",\n      cherry: "Cherry",\n    }}\n  />\n));'
  }
  lang="tsx"
>
  <Select
    id="basic-fruit"
    label="Fruit"
    value="apple"
    items={{
      apple: "Apple",
      banana: "Banana",
      cherry: "Cherry",
    }}
  />
</Preview>

### Sizes

Use the `size` prop to match Input sizing: `xs`, `sm`, `base`, and `lg`.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nconst items = {\n  apple: "Apple",\n  banana: "Banana",\n  cherry: "Cherry",\n};\n\nexport default ilha.render(() => (\n  <div class="flex w-full max-w-sm flex-col gap-3">\n    <Select\n      size="xs"\n      aria-label="Extra small select"\n      value="apple"\n      items={items}\n    />\n    <Select\n      size="sm"\n      aria-label="Small select"\n      value="apple"\n      items={items}\n    />\n    <Select\n      size="base"\n      aria-label="Base select"\n      value="apple"\n      items={items}\n    />\n    <Select\n      size="lg"\n      aria-label="Large select"\n      value="apple"\n      items={items}\n    />\n  </div>\n));'
  }
  lang="tsx"
  codeOnly
/>

### Without Visible Label

When a visible label is not needed, use `aria-label` for accessibility.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    aria-label="Select fruit"\n    value="banana"\n    items={{\n      apple: "Apple",\n      banana: "Banana",\n      cherry: "Cherry",\n    }}\n  />\n));'
  }
  lang="tsx"
>
  <Select
    aria-label="Select fruit"
    value="banana"
    items={{
      apple: "Apple",
      banana: "Banana",
      cherry: "Cherry",
    }}
  />
</Preview>

### With Description and Error

`Select` can show description text and validation errors. Error styling is automatically applied when the `error` prop is truthy.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    id="issue-type"\n    label="Issue type"\n    description="Choose the category that best matches your report."\n    error="Select an issue type before continuing."\n    placeholder="Choose an issue type"\n    items={{\n      bug: "Bug",\n      documentation: "Documentation",\n      feature: "Feature",\n    }}\n  />\n));'
  }
  lang="tsx"
>
  <Select
    id="issue-type"
    label="Issue type"
    description="Choose the category that best matches your report."
    error="Select an issue type before continuing."
    placeholder="Choose an issue type"
    items={{
      bug: "Bug",
      documentation: "Documentation",
      feature: "Feature",
    }}
  />
</Preview>

### Placeholder

Use the `placeholder` prop to render a placeholder option before the selectable items.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    id="priority"\n    label="Priority"\n    placeholder="Choose priority"\n    items={{\n      low: "Low",\n      medium: "Medium",\n      high: "High",\n      critical: "Critical",\n    }}\n  />\n));'
  }
  lang="tsx"
>
  <Select
    id="priority"
    label="Priority"
    placeholder="Choose priority"
    items={{
      low: "Low",
      medium: "Medium",
      high: "High",
      critical: "Critical",
    }}
  />
</Preview>

### Label with Tooltip

Use `labelTooltip` to add additional context via a native `title` attribute on the label.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    id="severity"\n    label="Severity"\n    labelTooltip="Choose the highest impact level that applies."\n    placeholder="Choose severity"\n    items={{\n      low: "Low",\n      medium: "Medium",\n      high: "High",\n      critical: "Critical",\n    }}\n  />\n));'
  }
  lang="tsx"
>
  <Select
    id="severity"
    label="Severity"
    labelTooltip="Choose the highest impact level that applies."
    placeholder="Choose severity"
    items={{
      low: "Low",
      medium: "Medium",
      high: "High",
      critical: "Critical",
    }}
  />
</Preview>

### Disabled

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    label="Fruit"\n    disabled\n    value="apple"\n    items={{\n      apple: "Apple",\n      banana: "Banana",\n      cherry: "Cherry",\n    }}\n  />\n));'
  }
  lang="tsx"
>
  <Select
    label="Fruit"
    disabled
    value="apple"
    items={{
      apple: "Apple",
      banana: "Banana",
      cherry: "Cherry",
    }}
  />
</Preview>

### Multiple Selection

Enable native multiple selection with the `multiple` prop. The select becomes a multi-row native control.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    id="columns"\n    label="Columns"\n    multiple\n    description="Hold Command or Control to select multiple options."\n    items={{\n      name: "Name",\n      location: "Location",\n      size: "Size",\n      read: "Read",\n      write: "Write",\n      createdAt: "Created At",\n    }}\n  />\n));'
  }
  lang="tsx"
>
  <Select
    id="columns"
    label="Columns"
    multiple
    description="Hold Command or Control to select multiple options."
    items={{
      name: "Name",
      location: "Location",
      size: "Size",
      read: "Read",
      write: "Write",
      createdAt: "Created At",
    }}
  />
</Preview>

### Disabled Options

Options can be disabled with descriptor objects in the `items` prop.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    id="plan-disabled"\n    label="Plan"\n    value="free"\n    items={{\n      free: "Free",\n      pro: "Pro",\n      business: { label: "Business", disabled: true },\n      enterprise: { label: "Enterprise", disabled: true },\n    }}\n  />\n));'
  }
  lang="tsx"
>
  <Select
    id="plan-disabled"
    label="Plan"
    value="free"
    items={{
      free: "Free",
      pro: "Pro",
      business: { label: "Business", disabled: true },
      enterprise: { label: "Enterprise", disabled: true },
    }}
  />
</Preview>

### Options as Children

Use `Select.Option` when you want explicit control over individual option markup.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    id="explicit-options"\n    label="Fruit"\n    placeholder="Choose fruit"\n  >\n    <Select.Option value="apple" label="Apple" />\n    <Select.Option value="banana" label="Banana" />\n    <Select.Option value="cherry" label="Cherry" />\n  </Select>\n));'
  }
  lang="tsx"
>
  <Select
    id="explicit-options"
    label="Fruit"
    placeholder="Choose fruit"
  >
    <Select.Option value="apple" label="Apple" />
    <Select.Option value="banana" label="Banana" />
    <Select.Option value="cherry" label="Cherry" />
  </Select>
</Preview>

### Grouped Options

Use `Select.Group` to organize related options under native `optgroup` labels.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    id="grouped-food"\n    label="Food"\n    placeholder="Choose food"\n  >\n    <Select.Group label="Fruits">\n      <Select.Option value="apple" label="Apple" />\n      <Select.Option value="banana" label="Banana" />\n    </Select.Group>\n    <Select.Group label="Vegetables">\n      <Select.Option value="carrot" label="Carrot" />\n      <Select.Option value="lettuce" label="Lettuce" />\n    </Select.Group>\n  </Select>\n));'
  }
  lang="tsx"
>
  <Select
    id="grouped-food"
    label="Food"
    placeholder="Choose food"
  >
    <Select.Group label="Fruits">
      <Select.Option value="apple" label="Apple" />
      <Select.Option value="banana" label="Banana" />
    </Select.Group>
    <Select.Group label="Vegetables">
      <Select.Option value="carrot" label="Carrot" />
      <Select.Option value="lettuce" label="Lettuce" />
    </Select.Group>
  </Select>
</Preview>

### Ghost Variant

Use `variant: "ghost"` for compact UIs where the select should blend into the surrounding surface.

<Preview
  code={
    'import ilha from "ilha";\nimport { Select } from "areia";\n\nexport default ilha.render(() => (\n  <Select\n    variant="ghost"\n    aria-label="Sort by"\n    value="updated"\n    items={{\n      updated: "Recently updated",\n      created: "Recently created",\n      name: "Name",\n    }}\n  />\n));'
  }
  lang="tsx"
>
  <Select
    variant="ghost"
    aria-label="Sort by"
    value="updated"
    items={{
      updated: "Recently updated",
      created: "Recently created",
      name: "Name",
    }}
  />
</Preview>

## API Reference

### Select

`Select` accepts standard HTML select attributes plus the following props.

| Prop            | Type                                                                                               | Default     | Description                                                               |
| --------------- | -------------------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------- |
| `class`         | `string`                                                                                           | -           | Additional CSS classes applied to the select.                             |
| `className`     | `string`                                                                                           | -           | Alias for `class`.                                                        |
| `size`          | `"xs" \| "sm" \| "base" \| "lg"`                                                                   | `"base"`    | Size of the select. Matches Input component sizes.                        |
| `variant`       | `"default" \| "error" \| "ghost"`                                                                  | `"default"` | Visual variant.                                                           |
| `label`         | `unknown`                                                                                          | -           | Label content for the select. Enables the field wrapper.                  |
| `placeholder`   | `string`                                                                                           | -           | Placeholder option shown before selectable items.                         |
| `items`         | `Record<string, SelectItemValue> \| Array<{ label: unknown; value: unknown; disabled?: boolean }>` | -           | Data structure of items rendered as options.                              |
| `children`      | `unknown`                                                                                          | -           | Explicit option markup. Prefer the second `Select` argument for options.  |
| second argument | `unknown[]`                                                                                        | -           | Option markup, usually `Select.Option(...)` or `Select.Group(...)` calls. |
| `description`   | `unknown`                                                                                          | -           | Helper text displayed below the select.                                   |
| `error`         | `unknown \| { message: unknown; match?: unknown }`                                                 | -           | Error message. When truthy, error styling is automatically applied.       |
| `disabled`      | `boolean`                                                                                          | -           | Whether the select is disabled.                                           |
| `required`      | `boolean`                                                                                          | -           | Whether the select is required. When `false`, shows optional text.        |
| `multiple`      | `boolean`                                                                                          | -           | Enables native multiple selection.                                        |

`Select.Root` and `Select.Static` are aliases for the base native select renderer.

### Select.Option

| Prop        | Type      | Default | Description                            |
| ----------- | --------- | ------- | -------------------------------------- |
| `label`     | `unknown` | -       | Option content.                        |
| `value`     | `unknown` | -       | Option value.                          |
| `disabled`  | `boolean` | -       | Whether the option cannot be selected. |
| `class`     | `string`  | -       | Additional CSS classes.                |
| `className` | `string`  | -       | Alias for `class`.                     |

### Select.Group

Groups related options together with a native `optgroup`.

| Prop            | Type        | Default | Description                                    |
| --------------- | ----------- | ------- | ---------------------------------------------- |
| `label`         | `string`    | -       | Visible optgroup label.                        |
| second argument | `unknown[]` | -       | Option markup.                                 |
| `disabled`      | `boolean`   | -       | Whether every option in the group is disabled. |

### Select.Separator

`Select.Separator()` renders a disabled option that can be used as a simple divider in native selects.

## Accessibility

### Label Requirement

Selects should have an accessible name via one of:

- `label` prop
- `aria-label` for selects without a visible label
- `aria-labelledby` for custom label association

### Native Behavior

Because `Select` uses the native `<select>` primitive, it keeps browser-provided keyboard navigation, form submission, and mobile picker behavior.

### Error Association

When an `id` is provided, descriptions and error messages are automatically associated with the select using `aria-describedby`.
