NativeSelect
The platform select, for when the operating system's own menu is the right answer.
@luc/uiExamples
Options as data
The platform's own select: no portal, no listbox, and it works before hydration — which is what a form on a slow connection needs.
<NativeSelect
aria-label="Universe"
defaultValue="us-large"
options={[
{ value: "us-large", label: "US large cap" },
{ value: "us-small", label: "US small cap" },
{ value: "global", label: "Global developed" },
]}
/>A placeholder
The placeholder is rendered as an empty, disabled first option, so it cannot be submitted as a choice.
<NativeSelect
aria-label="Universe"
placeholder="Choose a universe"
options={[
{ value: "us-large", label: "US large cap" },
{ value: "us-small", label: "US small cap" },
{ value: "global", label: "Global developed" },
]}
/>A disabled option
Options carry their own `disabled`, which a native menu greys out and refuses to select.
<NativeSelect
aria-label="Universe"
defaultValue="us-large"
options={[
{ value: "us-large", label: "US large cap" },
{ value: "us-small", label: "US small cap" },
{ value: "global", label: "Global developed" },
{ value: "private", label: "Private mandates", disabled: true },
]}
/>Sizes and states
`sm`, `md` and `lg` follow the same density scale as every other control; `invalid` and `disabled` are the same two states as `Input`.
<NativeSelect
aria-label="Small universe"
size="sm"
defaultValue="global"
options={[
{ value: "us-large", label: "US large cap" },
{ value: "us-small", label: "US small cap" },
{ value: "global", label: "Global developed" },
]}
/>Usage
import { NativeSelect } from "@luc/ui";<NativeSelect aria-label="Universe" defaultValue="us-large" options={universes} />Package setup — peer requirements, the stylesheet and the provider — is on installation.
API
Read from the published TypeScript API, so a prop that is not listed here does not exist and a default that is listed is the one the compiler sees.
| Export | Kind | Signature |
|---|---|---|
NativeSelect | 4 documented props | ({ className, size, invalid, options, placeholder, id, disabled, required, "aria-describedby": ariaDescribedBy, children, ...props }: NativeSelectProps) => import("@types/react").JSX.Element |
NativeSelect props
Type: NativeSelectProps
Values the compiler reads from the declaration.
| Prop | Type | Default | Notes |
|---|---|---|---|
invalid? | boolean | undefined | — | |
options? | { value: string; label: string; disabled?: boolean; }[] | undefined | — | Options as data — or pass `<option>` children, both work. |
placeholder? | string | undefined | — | Rendered as an empty, disabled first option. |
size? | "sm" | "md" | "lg" | undefined | — |
Guidelines
Do
- Reach for the platform select when the list is short, the answer is obvious and the OS menu is the right instrument — it works before hydration.
- Pass `options` as data, or write `<option>` children; both are supported and both are read by the compiler's prop table.
- Use `placeholder` for an empty first option that cannot be submitted as a choice.
Don't
- Use a native select for a searchable or grouped list — that is `Select` or `Combobox`.
- Style the popup: the open menu belongs to the operating system, and the closed control is the part you own.
- Rely on the placeholder as a label; it disappears as soon as an option is chosen.
Accessibility
This is the operating system's own control: keyboard behaviour, type-ahead and screen-reader announcement are the platform's, and `placeholder` is rendered as a disabled option rather than as a visual hint. `invalid` and `disabled` draw the same treatments as `Input`.
Family
Forms
Inputs, their validation surfaces and the form lifecycle around them.
24 documented entries in this family. Open the family index
Related