Skip to content

Select

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

Source Code

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

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <Select
    id="fruit"
    label="Fruit"
    value="apple"
    items={{
      apple: "Apple",
      banana: "Banana",
      cherry: "Cherry",
    }}
  />
));

Import

import { Select } from "areia";

Usage

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <Select
    id="plan"
    label="Plan"
    placeholder="Choose a plan"
    items={{
      free: "Free",
      pro: "Pro",
      team: "Team",
    }}
  />
));

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.

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <Select
    id="basic-fruit"
    label="Fruit"
    value="apple"
    items={{
      apple: "Apple",
      banana: "Banana",
      cherry: "Cherry",
    }}
  />
));

Sizes

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

import ilha from "ilha";
import { Select } from "areia";

const items = {
  apple: "Apple",
  banana: "Banana",
  cherry: "Cherry",
};

export default ilha.render(() => (
  <div class="flex w-full max-w-sm flex-col gap-3">
    <Select
      size="xs"
      aria-label="Extra small select"
      value="apple"
      items={items}
    />
    <Select
      size="sm"
      aria-label="Small select"
      value="apple"
      items={items}
    />
    <Select
      size="base"
      aria-label="Base select"
      value="apple"
      items={items}
    />
    <Select
      size="lg"
      aria-label="Large select"
      value="apple"
      items={items}
    />
  </div>
));

Without Visible Label

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

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <Select
    aria-label="Select fruit"
    value="banana"
    items={{
      apple: "Apple",
      banana: "Banana",
      cherry: "Cherry",
    }}
  />
));

With Description and Error

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

Choose the category that best matches your report.

Select an issue type before continuing.
import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <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",
    }}
  />
));

Placeholder

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

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <Select
    id="priority"
    label="Priority"
    placeholder="Choose priority"
    items={{
      low: "Low",
      medium: "Medium",
      high: "High",
      critical: "Critical",
    }}
  />
));

Label with Tooltip

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

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <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",
    }}
  />
));

Disabled

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <Select
    label="Fruit"
    disabled
    value="apple"
    items={{
      apple: "Apple",
      banana: "Banana",
      cherry: "Cherry",
    }}
  />
));

Multiple Selection

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

Hold Command or Control to select multiple options.

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <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",
    }}
  />
));

Disabled Options

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

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <Select
    id="plan-disabled"
    label="Plan"
    value="free"
    items={{
      free: "Free",
      pro: "Pro",
      business: { label: "Business", disabled: true },
      enterprise: { label: "Enterprise", disabled: true },
    }}
  />
));

Options as Children

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

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <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>
));

Grouped Options

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

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <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>
));

Ghost Variant

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

import ilha from "ilha";
import { Select } from "areia";

export default ilha.render(() => (
  <Select
    variant="ghost"
    aria-label="Sort by"
    value="updated"
    items={{
      updated: "Recently updated",
      created: "Recently created",
      name: "Name",
    }}
  />
));

API Reference

Select

Select accepts standard HTML select attributes plus the following props.

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

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

Select.Option

PropTypeDefaultDescription
labelunknown-Option content.
valueunknown-Option value.
disabledboolean-Whether the option cannot be selected.
classstring-Additional CSS classes.
classNamestring-Alias for class.

Select.Group

Groups related options together with a native optgroup.

PropTypeDefaultDescription
labelstring-Visible optgroup label.
second argumentunknown[]-Option markup.
disabledboolean-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.