Skip to content

Native select

Picks one option with the browser's own select.

Library
What’s this?

Installation

pnpm dlx shadcn@latest add @wisty/native-select

The CLI installs the Radix or Base UI file to match your project.

If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.

When to use

Use it

  • People pick one option from a short, fixed list, and the browser's own list is fine.
  • The form must work on touch devices with the system picker, or without JavaScript.
  • The options come in groups, like inbound and outbound lead sources.

Don't use it

  • The list should look like the rest of the app, or options need icons or descriptions. Use Select.
  • The list is long or people should search it. Use Combobox.
  • People may pick several options. Use checkboxes.
  • There are two to five options and room to show them all. Use Radio group.

Usage

NativeSelect
├── NativeSelectOption
└── NativeSelectOptGroup
    └── NativeSelectOption

Pass id to NativeSelect, so a label's htmlFor reaches the select. Start with an empty option when people must choose.

import { Field, FieldLabel } from "@/components/ui/field"
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select"
<Field>
  <FieldLabel htmlFor="rating">Rating</FieldLabel>
  <NativeSelect id="rating" defaultValue="">
    <NativeSelectOption value="">Select an option</NativeSelectOption>
    <NativeSelectOption value="hot">Hot</NativeSelectOption>
    <NativeSelectOption value="cold">Cold</NativeSelectOption>
  </NativeSelect>
</Field>

className goes to the wrapper around the select, so width classes size the whole field. Every other prop goes to the select.

Examples

States

One with `aria-invalid` and an error message it points to, and one `disabled`.

Sizes

The default and small selects, set with `size` on `NativeSelect`.

API reference

PartBuilt on
NativeSelect<select> (opens in a new tab)
NativeSelectOption<option> (opens in a new tab)
NativeSelectOptGroup<optgroup> (opens in a new tab)

NativeSelect

PropTypeDefault
size"sm" | "default""default"

SLDS mapping

NativeSelect is slds-select_container around slds-select, drawn with the input's frame. aria-invalid is slds-has-error, and disabled is SLDS's gray disabled field, not dimmed. Options and option groups keep the browser's colors.

Known gaps:

  • SLDS draws two small triangles, up and down. This draws one chevron.
PropValueSLDSNotes
sizedefaultslds-select_container slds-select32px, like an input.
sizesmnoneSLDS has one select height. 28px, like a small button.

Accessibility

  • Name it with a visible label. The empty first option isn't a label.
  • Pair aria-invalid with an error message the select points to through aria-describedby.
  • In Cosmos dark, text in an invalid select is about 4.3:1 against its background, below AA. Salesforce's own stylesheet fails the same way.

Responsive behavior

  • In a vertical Field it fills the column. Elsewhere it's as wide as its longest option; add w-full to fill its container.
  • When the field is narrower than an option, the option's text is cut off before the chevron.
  • On touch screens the text is larger, so iOS Safari doesn't zoom in on focus. Don't set a smaller text size on it.

Rules

  • Use NativeSelectOption and NativeSelectOptGroup, not bare option and optgroup, so the options keep readable colors in dark mode.
  • Show errors with aria-invalid. Don't add border or color classes.