# Native Select

A styled native select element.

Source: [native-select.tsx](https://github.com/jakejarvis/jarvis-ui/blob/main/src/components/ui/native-select.tsx)

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

export default function NativeSelectBasic() {
  return (
    <NativeSelect aria-label="Status" defaultValue="in-progress">
      <NativeSelectOption value="backlog">Backlog</NativeSelectOption>
      <NativeSelectOption value="todo">To do</NativeSelectOption>
      <NativeSelectOption value="in-progress">In progress</NativeSelectOption>
      <NativeSelectOption value="done">Done</NativeSelectOption>
    </NativeSelect>
  );
}
```

## Installation

Add the registry, once per project:

```bash
npx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json
```

Then add the component:

```bash
npx shadcn@latest add @jarvis/native-select
```

## Usage

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

export function SizeSelect() {
  return (
    <NativeSelect aria-label="Size" defaultValue="m">
      <NativeSelectOption value="s">Small</NativeSelectOption>
      <NativeSelectOption value="m">Medium</NativeSelectOption>
      <NativeSelectOption value="l">Large</NativeSelectOption>
    </NativeSelect>
  );
}
```

A native select uses the platform's own picker, which works well on phones. Its options can only
be text; for anything richer, use a [Select](https://ui.jarv.is/components/select.md).

## Composition

- `NativeSelect`
  - `NativeSelectOption`
  - `NativeSelectOptGroup`

## Examples

### With a label

A `FieldLabel` in the same `Field` names the select. Without one, give it an `aria-label`.

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

export default function NativeSelectWithLabel() {
  return (
    <Field className="w-full max-w-sm">
      <FieldLabel htmlFor="region">Region</FieldLabel>
      <NativeSelect id="region" defaultValue="us" className="w-full">
        <NativeSelectOption value="us">United States</NativeSelectOption>
        <NativeSelectOption value="eu">Europe</NativeSelectOption>
        <NativeSelectOption value="ap">Asia Pacific</NativeSelectOption>
      </NativeSelect>
    </Field>
  );
}
```

### Sizes

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

export default function NativeSelectSizes() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      <NativeSelect size="sm" aria-label="Rows per page" defaultValue="25">
        <NativeSelectOption value="10">10 rows</NativeSelectOption>
        <NativeSelectOption value="25">25 rows</NativeSelectOption>
        <NativeSelectOption value="50">50 rows</NativeSelectOption>
      </NativeSelect>
      <NativeSelect aria-label="Rows per page" defaultValue="25">
        <NativeSelectOption value="10">10 rows</NativeSelectOption>
        <NativeSelectOption value="25">25 rows</NativeSelectOption>
        <NativeSelectOption value="50">50 rows</NativeSelectOption>
      </NativeSelect>
      <NativeSelect size="lg" aria-label="Rows per page" defaultValue="25">
        <NativeSelectOption value="10">10 rows</NativeSelectOption>
        <NativeSelectOption value="25">25 rows</NativeSelectOption>
        <NativeSelectOption value="50">50 rows</NativeSelectOption>
      </NativeSelect>
    </div>
  );
}
```

### Groups

Group options with `NativeSelectOptGroup`.

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

export default function NativeSelectGroups() {
  return (
    <NativeSelect aria-label="Time zone" defaultValue="">
      <NativeSelectOption value="" disabled>
        Select a time zone
      </NativeSelectOption>
      <NativeSelectOptGroup label="Americas">
        <NativeSelectOption value="america-los-angeles">Pacific Time</NativeSelectOption>
        <NativeSelectOption value="america-denver">Mountain Time</NativeSelectOption>
        <NativeSelectOption value="america-chicago">Central Time</NativeSelectOption>
        <NativeSelectOption value="america-new-york">Eastern Time</NativeSelectOption>
      </NativeSelectOptGroup>
      <NativeSelectOptGroup label="Europe">
        <NativeSelectOption value="europe-london">London</NativeSelectOption>
        <NativeSelectOption value="europe-berlin">Berlin</NativeSelectOption>
        <NativeSelectOption value="europe-helsinki">Helsinki</NativeSelectOption>
      </NativeSelectOptGroup>
      <NativeSelectOptGroup label="Asia Pacific">
        <NativeSelectOption value="asia-singapore">Singapore</NativeSelectOption>
        <NativeSelectOption value="asia-tokyo">Tokyo</NativeSelectOption>
        <NativeSelectOption value="australia-sydney">Sydney</NativeSelectOption>
      </NativeSelectOptGroup>
    </NativeSelect>
  );
}
```

### Disabled

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

export default function NativeSelectDisabled() {
  return (
    <NativeSelect aria-label="Region" disabled>
      <NativeSelectOption value="us">United States</NativeSelectOption>
    </NativeSelect>
  );
}
```

### Invalid

Set `invalid` on the `Field` and explain the problem with a `FieldError`.

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

export default function NativeSelectInvalid() {
  return (
    <Field invalid className="w-fit">
      <FieldLabel>Country</FieldLabel>
      <NativeSelect defaultValue="">
        <NativeSelectOption value="" disabled>
          Select a country
        </NativeSelectOption>
        <NativeSelectOption value="ca">Canada</NativeSelectOption>
        <NativeSelectOption value="de">Germany</NativeSelectOption>
        <NativeSelectOption value="jp">Japan</NativeSelectOption>
      </NativeSelect>
      <FieldError>Choose a country.</FieldError>
    </Field>
  );
}
```

## Props

`className` goes to the wrapper `<div>`, so set the width there.

| Part | Extends |
| --- | --- |
| `NativeSelect` | `<select>` |
| `NativeSelectOption` | `<option>` |
| `NativeSelectOptGroup` | `<optgroup>` |

The tables leave out `className`, `style` and `render`. Parts built on Base UI take them as its [styling](https://base-ui.com/react/handbook/styling) and [composition](https://base-ui.com/react/handbook/composition) guides describe.

### NativeSelect

| Prop    | Type                        | Description          |
| ------- | --------------------------- | -------------------- |
| `size?` | `"default" \| "lg" \| "sm"` | Default: `"default"` |
