Native Select
The browser's own select element, styled like the other form controls, for picking one option from a list.
@zenoxai/ui/components/native-select Markdown<NativeSelect defaultValue="high" aria-label="Minimum severity">
<NativeSelectOption value="critical">Critical</NativeSelectOption>
<NativeSelectOption value="high">High and above</NativeSelectOption>
<NativeSelectOption value="medium">Medium and above</NativeSelectOption>
<NativeSelectOption value="low">All severities</NativeSelectOption>
</NativeSelect>Usage
import {
NativeSelect,
NativeSelectOption,
} from "@zenoxai/ui/components/native-select"
<NativeSelect defaultValue="weekly">
<NativeSelectOption value="daily">Daily</NativeSelectOption>
<NativeSelectOption value="weekly">Weekly</NativeSelectOption>
</NativeSelect>
NativeSelect renders a real <select>, so the option list is the operating system’s: a
wheel on iOS, a sheet on Android, a plain menu on the desktop. It submits with a form, works
before JavaScript loads and needs no portal.
Choose it over Select on touch-first screens, in long server-rendered forms, and when the options are plain text. Choose Select when options need icons, descriptions or the platform’s popup styling, and Combobox when the user needs to search the list.
All <select> attributes pass through to the element: value, onChange, name,
required, disabled, aria-*. className goes to the wrapper <div>, which also holds the
chevron icon.
Examples
With a label
Wrap it in a Field and point the FieldLabel at the select’s id. In a
vertical field the select fills the width.
Reports are sent on Monday at 08:00 UTC.
<Field className="max-w-xs">
<FieldLabel htmlFor="report-frequency">Report frequency</FieldLabel>
<NativeSelect id="report-frequency" defaultValue="weekly">
<NativeSelectOption value="daily">Daily</NativeSelectOption>
<NativeSelectOption value="weekly">Weekly</NativeSelectOption>
<NativeSelectOption value="monthly">Monthly</NativeSelectOption>
</NativeSelect>
<FieldDescription>
Reports are sent on Monday at 08:00 UTC.
</FieldDescription>
</Field>Groups
NativeSelectOptGroup renders an <optgroup> with a label.
<NativeSelect defaultValue="7d" aria-label="Time range">
<NativeSelectOptGroup label="Relative">
<NativeSelectOption value="24h">Last 24 hours</NativeSelectOption>
<NativeSelectOption value="7d">Last 7 days</NativeSelectOption>
<NativeSelectOption value="30d">Last 30 days</NativeSelectOption>
</NativeSelectOptGroup>
<NativeSelectOptGroup label="Calendar">
<NativeSelectOption value="this-month">This month</NativeSelectOption>
<NativeSelectOption value="last-month">Last month</NativeSelectOption>
<NativeSelectOption value="this-quarter">
This quarter
</NativeSelectOption>
</NativeSelectOptGroup>
</NativeSelect>Sizes
size="sm" (28px) fits toolbars and filter bars, default (32px) is the form size and lg
(36px) matches a large Input or Button. The chevron is 14px at sm and 16px otherwise. The
native size attribute (number of visible rows) is not available. Below the md breakpoint
the text is 16px, as in Input, so iOS does not zoom the page when the select takes focus.
<>
<NativeSelect size="sm" defaultValue="open" aria-label="Status (small)">
<NativeSelectOption value="open">Open</NativeSelectOption>
<NativeSelectOption value="closed">Closed</NativeSelectOption>
</NativeSelect>
<NativeSelect defaultValue="open" aria-label="Status">
<NativeSelectOption value="open">Open</NativeSelectOption>
<NativeSelectOption value="closed">Closed</NativeSelectOption>
</NativeSelect>
<NativeSelect size="lg" defaultValue="open" aria-label="Status (large)">
<NativeSelectOption value="open">Open</NativeSelectOption>
<NativeSelectOption value="closed">Closed</NativeSelectOption>
</NativeSelect>
</>Disabled and invalid
Set disabled on the select and data-disabled on the Field. For an error, set
aria-invalid on the select and data-invalid on the Field. A first option with an empty
value and disabled works as a placeholder that the user cannot pick back.
<div className="grid w-full max-w-xs gap-4">
<Field data-disabled>
<FieldLabel htmlFor="data-region">Data region</FieldLabel>
<NativeSelect id="data-region" defaultValue="eu" disabled>
<NativeSelectOption value="eu">Europe (Frankfurt)</NativeSelectOption>
<NativeSelectOption value="us">
United States (Virginia)
</NativeSelectOption>
</NativeSelect>
</Field>
<Field data-invalid>
<FieldLabel htmlFor="escalation-owner">Escalation owner</FieldLabel>
<NativeSelect
id="escalation-owner"
defaultValue=""
aria-invalid
aria-describedby="escalation-owner-error"
>
<NativeSelectOption value="" disabled>
Select a team
</NativeSelectOption>
<NativeSelectOption value="soc">SOC tier 1</NativeSelectOption>
<NativeSelectOption value="ir">Incident response</NativeSelectOption>
</NativeSelect>
<FieldError id="escalation-owner-error">
Select the team that handles escalations.
</FieldError>
</Field>
</div>Accessibility
- Keyboard, screen reader and touch behavior are the browser’s, so they match what users know from every other site.
- Name the select with a
FieldLabelandhtmlFor, or witharia-labelwhen there is no visible label. - The chevron is decorative and hidden from assistive technology.
API reference
Generated from the TypeScript source. className, style and children are accepted everywhere and omitted below.
NativeSelect
NativeSelect is the browser's own <select>, styled like Input, with NativeSelectOption and NativeSelectOptGroup inside. It suits mobile forms, where the system picker is easier to use; for a styled popup with richer items, use Select.
| Prop | Type | Default |
|---|---|---|
size | "default" | "sm" | "lg"Height: `sm` 28px, `default` 32px, `lg` 36px, the heights of Input and Button. The chevron is 14px at `sm`, 16px otherwise. | default |
NativeSelectOptGroup
NativeSelectOptGroup groups options under a label, as an <optgroup>.
No props of its own. Accepts the props of the element it renders.
NativeSelectOption
NativeSelectOption is one <option> of a NativeSelect.
No props of its own. Accepts the props of the element it renders.