Native Select

A native select styled to fit the rest of the kit.

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 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

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

Usage

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
    └── 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.

Please choose a valid option.

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.

API Reference

NativeSelect

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

PropTypeDefault
size"default" | "sm""default"
disabledboolean
aria-invalidboolean
classNamestring
<NativeSelect defaultValue="apple">  <NativeSelectOption value="apple">Apple</NativeSelectOption>  <NativeSelectOption value="banana">Banana</NativeSelectOption></NativeSelect>

NativeSelectOption

PropTypeDefault
valuestring
disabledbooleanfalse
classNamestring
<NativeSelectOption value="apple">Apple</NativeSelectOption>

NativeSelectOptGroup

PropTypeDefault
labelstring
disabledbooleanfalse
classNamestring
<NativeSelectOptGroup label="Fruit">  <NativeSelectOption value="apple">Apple</NativeSelectOption></NativeSelectOptGroup>