---
title: Native Select
description: A native select styled to fit the rest of the kit.
group: Components
order: 49
---

A native `<select>` with light chrome and familiar browser behavior.

```card
title: Looking for Select?
description: Need a custom panel, animation, or richer interaction? Use Select instead.
href: /docs/components/select
label: View Select
```

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

export function Example() {
  return (
    <NativeSelect defaultValue="todo" aria-label="Select status">
      <NativeSelectOption value="todo">Todo</NativeSelectOption>
      <NativeSelectOption value="in-progress">In Progress</NativeSelectOption>
      <NativeSelectOption value="done">Done</NativeSelectOption>
      <NativeSelectOption value="cancelled">Cancelled</NativeSelectOption>
    </NativeSelect>
  )
}
```

## Installation

```bash
npx @arctis-sh/@arctis-sh/ui@latest add native-select
```

## Usage

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

```tsx
<NativeSelect>
  <NativeSelectOption value="">Select a fruit</NativeSelectOption>
  <NativeSelectOption value="apple">Apple</NativeSelectOption>
  <NativeSelectOption value="banana">Banana</NativeSelectOption>
  <NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
  <NativeSelectOption value="pineapple">Pineapple</NativeSelectOption>
</NativeSelect>
```

## Composition

### Simple

Place options directly under `NativeSelect` when you do not need groups.

```tree
NativeSelect
├── NativeSelectOption
├── NativeSelectOption
├── NativeSelectOption
└── NativeSelectOption
```

### With groups

Use `NativeSelectOptGroup` to organize options into categories.

```tree
NativeSelect
├── NativeSelectOptGroup
│   ├── NativeSelectOption
│   └── NativeSelectOption
└── NativeSelectOptGroup
    ├── NativeSelectOption
    └── NativeSelectOption
```

## Basic

A straightforward list with a default value.

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

export function Example() {
  return (
    <NativeSelect defaultValue="todo" aria-label="Select status">
      <NativeSelectOption value="todo">Todo</NativeSelectOption>
      <NativeSelectOption value="in-progress">In Progress</NativeSelectOption>
      <NativeSelectOption value="done">Done</NativeSelectOption>
      <NativeSelectOption value="cancelled">Cancelled</NativeSelectOption>
    </NativeSelect>
  )
}
```

## Groups

Use `NativeSelectOptGroup` to organize options into categories.

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

export function Example() {
  return (
    <NativeSelect defaultValue="" aria-label="Select department">
      <NativeSelectOption value="">Select department</NativeSelectOption>
      <NativeSelectOptGroup label="Engineering">
        <NativeSelectOption value="frontend">Frontend</NativeSelectOption>
        <NativeSelectOption value="backend">Backend</NativeSelectOption>
        <NativeSelectOption value="devops">DevOps</NativeSelectOption>
      </NativeSelectOptGroup>
      <NativeSelectOptGroup label="Sales">
        <NativeSelectOption value="sales-rep">Sales Rep</NativeSelectOption>
        <NativeSelectOption value="account-manager">
          Account Manager
        </NativeSelectOption>
        <NativeSelectOption value="sales-director">
          Sales Director
        </NativeSelectOption>
      </NativeSelectOptGroup>
      <NativeSelectOptGroup label="Operations">
        <NativeSelectOption value="support">
          Customer Support
        </NativeSelectOption>
        <NativeSelectOption value="product">
          Product Manager
        </NativeSelectOption>
        <NativeSelectOption value="ops">Operations Manager</NativeSelectOption>
      </NativeSelectOptGroup>
    </NativeSelect>
  )
}
```

## Disabled

Set `disabled` on `NativeSelect` to lock the control.

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

export function Example() {
  return (
    <NativeSelect disabled defaultValue="apple" aria-label="Fruit">
      <NativeSelectOption value="apple">Apple</NativeSelectOption>
      <NativeSelectOption value="banana">Banana</NativeSelectOption>
      <NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
    </NativeSelect>
  )
}
```

## Invalid

Pass `aria-invalid` for error styling. Pair it with a destructive label and helper text when the field has an error.

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

export function Example() {
  return (
    <div className="grid w-fit gap-1.5">
      <label
        htmlFor="fruit-invalid"
        className="text-sm font-medium tracking-wide text-destructive"
      >
        Fruit
      </label>
      <NativeSelect
        id="fruit-invalid"
        defaultValue="apple"
        aria-invalid
        aria-label="Fruit"
      >
        <NativeSelectOption value="apple">Apple</NativeSelectOption>
        <NativeSelectOption value="banana">Banana</NativeSelectOption>
        <NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
      </NativeSelect>
      <p className="text-sm text-destructive">Please choose a valid option.</p>
    </div>
  )
}
```

## Native Select vs Select

- Prefer `NativeSelect` for native browser behavior, lighter weight, or mobile OS pickers.
- Prefer `Select` for custom panels, animations, or complex interactions. See [Select](/docs/components/select).

## API Reference

### NativeSelect

Wraps a native HTML `select`. Chevron is decorative. Hover matches outline button (`hover:bg-muted`). `className` applies to the wrapper.

| Prop | Type | Default |
| --- | --- | --- |
| size | "default" \| "sm" | "default" |
| disabled | boolean | — |
| aria-invalid | boolean | — |
| className | string | — |

```tsx
<NativeSelect defaultValue="apple">
  <NativeSelectOption value="apple">Apple</NativeSelectOption>
  <NativeSelectOption value="banana">Banana</NativeSelectOption>
</NativeSelect>
```

### NativeSelectOption

| Prop | Type | Default |
| --- | --- | --- |
| value | string | — |
| disabled | boolean | false |
| className | string | — |

```tsx
<NativeSelectOption value="apple">Apple</NativeSelectOption>
```

### NativeSelectOptGroup

| Prop | Type | Default |
| --- | --- | --- |
| label | string | — |
| disabled | boolean | false |
| className | string | — |

```tsx
<NativeSelectOptGroup label="Fruit">
  <NativeSelectOption value="apple">Apple</NativeSelectOption>
</NativeSelectOptGroup>
```

## Source

```tsx
import type { ComponentProps } from "react";
import { cn } from "@/lib/utils";

type NativeSelectProps = Omit<ComponentProps<"select">, "size"> & {
  size?: "sm" | "default";
};

function NativeSelect({
  className,
  size = "default",
  ...props
}: NativeSelectProps) {
  return (
    <div
      data-slot="native-select-wrapper"
      data-size={size}
      className={cn(
        "group/native-select relative w-full has-[select:disabled]:opacity-40",
        className,
      )}
    >
      <select
        data-slot="native-select"
        data-size={size}
        className={cn(
          "w-full min-w-0 appearance-none rounded-md border border-border bg-muted pr-8 pl-3 text-sm tracking-wide text-foreground transition-colors duration-200 ease-out outline-none disabled:pointer-events-none disabled:cursor-not-allowed aria-invalid:border-destructive aria-invalid:bg-destructive/5",
          size === "default" && "h-9 py-1",
          size === "sm" && "h-8 py-0.5",
        )}
        {...props}
      />
      <ChevronDownIcon
        data-slot="native-select-icon"
        className="pointer-events-none absolute top-1/2 right-2.5 size-4 -translate-y-1/2 text-muted-foreground"
      />
    </div>
  );
}

type NativeSelectOptionProps = ComponentProps<"option">;

function NativeSelectOption({ className, ...props }: NativeSelectOptionProps) {
  return (
    <option
      data-slot="native-select-option"
      className={cn("bg-surface text-foreground", className)}
      {...props}
    />
  );
}

type NativeSelectOptGroupProps = ComponentProps<"optgroup">;

function NativeSelectOptGroup({
  className,
  ...props
}: NativeSelectOptGroupProps) {
  return (
    <optgroup
      data-slot="native-select-optgroup"
      className={cn("bg-surface text-foreground", className)}
      {...props}
    />
  );
}

function ChevronDownIcon({
  className,
  ...props
}: ComponentProps<"svg">) {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      aria-hidden
      className={cn("size-4", className)}
      {...props}
    >
      <path d="m6 9 6 6 6-6" />
    </svg>
  );
}

export { NativeSelect, NativeSelectOption, NativeSelectOptGroup };
```
