# Native Select

The browser's own select element, styled like the other form controls, for picking one option from a list.

```tsx
import { NativeSelect, NativeSelectOption } from "@zenoxai/ui/components/native-select"

function NativeSelectDemo() {
  return (
    <NativeSelect defaultValue="high" aria-label="Minimum severity">
      <NativeSelectOption value="critical">Critical</NativeSelectOption>
      <NativeSelectOption value="high">High and above</NativeSelectOption>
      <NativeSelectOption value="medium">Medium and above</NativeSelectOption>
      <NativeSelectOption value="low">All severities</NativeSelectOption>
    </NativeSelect>
  )
}
```

## Usage

```tsx
import {
  NativeSelect,
  NativeSelectOption,
} from "@zenoxai/ui/components/native-select"

<NativeSelect defaultValue="weekly">
  <NativeSelectOption value="daily">Daily</NativeSelectOption>
  <NativeSelectOption value="weekly">Weekly</NativeSelectOption>
</NativeSelect>
```

`NativeSelect` renders a real `<select>`, so the option list is the operating system's: a
wheel on iOS, a sheet on Android, a plain menu on the desktop. It submits with a form, works
before JavaScript loads and needs no portal.

Choose it over [Select](/components/select) on touch-first screens, in long server-rendered
forms, and when the options are plain text. Choose [Select](/components/select) when options
need icons, descriptions or the platform's popup styling, and
[Combobox](/components/combobox) when the user needs to search the list.

All `<select>` attributes pass through to the element: `value`, `onChange`, `name`,
`required`, `disabled`, `aria-*`. `className` goes to the wrapper `<div>`, which also holds the
chevron icon.

## Examples

### With a label

Wrap it in a [Field](/components/field) and point the `FieldLabel` at the select's `id`. In a
vertical field the select fills the width.

```tsx
import { Field, FieldDescription, FieldLabel } from "@zenoxai/ui/components/field"
import { NativeSelect, NativeSelectOption } from "@zenoxai/ui/components/native-select"

function NativeSelectWithLabel() {
  return (
    <Field className="max-w-xs">
      <FieldLabel htmlFor="report-frequency">Report frequency</FieldLabel>
      <NativeSelect id="report-frequency" defaultValue="weekly">
        <NativeSelectOption value="daily">Daily</NativeSelectOption>
        <NativeSelectOption value="weekly">Weekly</NativeSelectOption>
        <NativeSelectOption value="monthly">Monthly</NativeSelectOption>
      </NativeSelect>
      <FieldDescription>
        Reports are sent on Monday at 08:00 UTC.
      </FieldDescription>
    </Field>
  )
}
```

### Groups

`NativeSelectOptGroup` renders an `<optgroup>` with a `label`.

```tsx
import { NativeSelect, NativeSelectOptGroup, NativeSelectOption } from "@zenoxai/ui/components/native-select"

function NativeSelectGroups() {
  return (
    <NativeSelect defaultValue="7d" aria-label="Time range">
      <NativeSelectOptGroup label="Relative">
        <NativeSelectOption value="24h">Last 24 hours</NativeSelectOption>
        <NativeSelectOption value="7d">Last 7 days</NativeSelectOption>
        <NativeSelectOption value="30d">Last 30 days</NativeSelectOption>
      </NativeSelectOptGroup>
      <NativeSelectOptGroup label="Calendar">
        <NativeSelectOption value="this-month">This month</NativeSelectOption>
        <NativeSelectOption value="last-month">Last month</NativeSelectOption>
        <NativeSelectOption value="this-quarter">
          This quarter
        </NativeSelectOption>
      </NativeSelectOptGroup>
    </NativeSelect>
  )
}
```

### Sizes

`size="sm"` (28px) fits toolbars and filter bars, `default` (32px) is the form size and `lg`
(36px) matches a large Input or Button. The chevron is 14px at `sm` and 16px otherwise. The
native `size` attribute (number of visible rows) is not available. Below the `md` breakpoint
the text is 16px, as in Input, so iOS does not zoom the page when the select takes focus.

```tsx
import { NativeSelect, NativeSelectOption } from "@zenoxai/ui/components/native-select"

function NativeSelectSizes() {
  return (
    <>
      <NativeSelect size="sm" defaultValue="open" aria-label="Status (small)">
        <NativeSelectOption value="open">Open</NativeSelectOption>
        <NativeSelectOption value="closed">Closed</NativeSelectOption>
      </NativeSelect>
      <NativeSelect defaultValue="open" aria-label="Status">
        <NativeSelectOption value="open">Open</NativeSelectOption>
        <NativeSelectOption value="closed">Closed</NativeSelectOption>
      </NativeSelect>
      <NativeSelect size="lg" defaultValue="open" aria-label="Status (large)">
        <NativeSelectOption value="open">Open</NativeSelectOption>
        <NativeSelectOption value="closed">Closed</NativeSelectOption>
      </NativeSelect>
    </>
  )
}
```

### Disabled and invalid

Set `disabled` on the select and `data-disabled` on the `Field`. For an error, set
`aria-invalid` on the select and `data-invalid` on the `Field`. A first option with an empty
value and `disabled` works as a placeholder that the user cannot pick back.

```tsx
import { Field, FieldError, FieldLabel } from "@zenoxai/ui/components/field"
import { NativeSelect, NativeSelectOption } from "@zenoxai/ui/components/native-select"

function NativeSelectStates() {
  return (
    <div className="grid w-full max-w-xs gap-4">
      <Field data-disabled>
        <FieldLabel htmlFor="data-region">Data region</FieldLabel>
        <NativeSelect id="data-region" defaultValue="eu" disabled>
          <NativeSelectOption value="eu">Europe (Frankfurt)</NativeSelectOption>
          <NativeSelectOption value="us">
            United States (Virginia)
          </NativeSelectOption>
        </NativeSelect>
      </Field>
      <Field data-invalid>
        <FieldLabel htmlFor="escalation-owner">Escalation owner</FieldLabel>
        <NativeSelect
          id="escalation-owner"
          defaultValue=""
          aria-invalid
          aria-describedby="escalation-owner-error"
        >
          <NativeSelectOption value="" disabled>
            Select a team
          </NativeSelectOption>
          <NativeSelectOption value="soc">SOC tier 1</NativeSelectOption>
          <NativeSelectOption value="ir">Incident response</NativeSelectOption>
        </NativeSelect>
        <FieldError id="escalation-owner-error">
          Select the team that handles escalations.
        </FieldError>
      </Field>
    </div>
  )
}
```

## Accessibility

- Keyboard, screen reader and touch behavior are the browser's, so they match what users know
  from every other site.
- Name the select with a `FieldLabel` and `htmlFor`, or with `aria-label` when there is no
  visible label.
- The chevron is decorative and hidden from assistive technology.

## API reference

`import { ... } from "@zenoxai/ui/components/native-select"`

### NativeSelect

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| size | `"default" \| "sm" \| "lg"` | `default` | Height: `sm` 28px, `default` 32px, `lg` 36px, the heights of Input and Button. The chevron is 14px at `sm`, 16px otherwise. |

### NativeSelectOptGroup

No props of its own.

### NativeSelectOption

No props of its own.

