A native <select> with light chrome and familiar browser behavior.
Looking for Select?
Need a custom panel, animation, or richer interaction? Use Select instead.
View Selectimport { 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
npx @arctis-sh/@arctis-sh/ui@latest add native-selectUsage
import { NativeSelect, NativeSelectOptGroup, NativeSelectOption,} from "@/components/ui/native-select"<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.
NativeSelect ├── NativeSelectOption ├── NativeSelectOption ├── NativeSelectOption └── NativeSelectOption
With groups
Use NativeSelectOptGroup to organize options into categories.
NativeSelect
├── NativeSelectOptGroup
│ ├── NativeSelectOption
│ └── NativeSelectOption
└── NativeSelectOptGroup
├── NativeSelectOption
└── NativeSelectOptionBasic
A straightforward list with a default value.
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.
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.
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.
Please choose a valid option.
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
NativeSelectfor native browser behavior, lighter weight, or mobile OS pickers. - Prefer
Selectfor custom panels, animations, or complex interactions. See 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 | — |
<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 | — |
<NativeSelectOption value="apple">Apple</NativeSelectOption>NativeSelectOptGroup
| Prop | Type | Default |
|---|---|---|
| label | string | — |
| disabled | boolean | false |
| className | string | — |
<NativeSelectOptGroup label="Fruit"> <NativeSelectOption value="apple">Apple</NativeSelectOption></NativeSelectOptGroup>