Inputs
Select
A native select dressed to match the other fields: same heights, border, focus ring and invalid state, with a chevron and an optional leading icon. It keeps the platform picker, which is the best option list on phones. For long, searchable lists use Combobox.
Where your data is stored.
<div className="mx-auto grid w-full max-w-lg gap-5 sm:grid-cols-2"> <Field label="Role"> <Select defaultValue="editor"> <option value="owner">Owner</option> <option value="admin">Admin</option> <option value="editor">Editor</option> <option value="viewer">Viewer</option> </Select> </Field> <Field label="Region" hint="Where your data is stored."> <Select icon={<Globe strokeWidth={1.75} />} defaultValue="eu-west"> <option value="eu-west">Europe (Frankfurt)</option> <option value="us-east">US East (Virginia)</option> <option value="ap-south">Asia Pacific (Singapore)</option> </Select> </Field></div>Usage
components/ui/select.tsx
import { Field } from "@/components/ui/field";import { Select } from "@/components/ui/select"; export function Example() { return ( <Field label="Currency"> <Select defaultValue="eur"> <option value="eur">Euro (EUR)</option> <option value="usd">US dollar (USD)</option> </Select> </Field> );}Examples
Overview
Where your data is stored.
<div className="mx-auto grid w-full max-w-lg gap-5 sm:grid-cols-2"> <Field label="Role"> <Select defaultValue="editor"> <option value="owner">Owner</option> <option value="admin">Admin</option> <option value="editor">Editor</option> <option value="viewer">Viewer</option> </Select> </Field> <Field label="Region" hint="Where your data is stored."> <Select icon={<Globe strokeWidth={1.75} />} defaultValue="eu-west"> <option value="eu-west">Europe (Frankfurt)</option> <option value="us-east">US East (Virginia)</option> <option value="ap-south">Asia Pacific (Singapore)</option> </Select> </Field></div>Placeholder and groups
placeholder adds a greyed, unselectable first option. Native optgroup works as usual.
<div className="mx-auto w-full max-w-sm"> <Field label="Time zone" required> <Select placeholder="Choose a time zone"> <optgroup label="Europe"> <option value="Europe/Lisbon">Lisbon (GMT+1)</option> <option value="Europe/Berlin">Berlin (GMT+2)</option> <option value="Europe/Istanbul">Istanbul (GMT+3)</option> </optgroup> <optgroup label="Americas"> <option value="America/New_York">New York (GMT−4)</option> <option value="America/Los_Angeles">Los Angeles (GMT−7)</option> </optgroup> </Select> </Field></div>Sizes
<div className="mx-auto flex w-full max-w-xs flex-col gap-3"> <Select size="sm" aria-label="Rows per page" defaultValue="25"> <option value="25">25 rows</option> <option value="50">50 rows</option> </Select> <Select size="md" aria-label="Sort by" defaultValue="due"> <option value="due">Sort by due date</option> <option value="amount">Sort by amount</option> </Select> <Select size="lg" aria-label="Plan" defaultValue="team"> <option value="team">Team plan</option> <option value="business">Business plan</option> </Select></div>States
Pick the country on your tax ID.
Managed by your organisation.
<div className="mx-auto grid w-full max-w-lg gap-5 sm:grid-cols-2"> <Field label="Billing country" error="Pick the country on your tax ID."> <Select placeholder="Select a country"> <option value="pt">Portugal</option> <option value="de">Germany</option> </Select> </Field> <Field label="Plan" hint="Managed by your organisation." disabled> <Select defaultValue="business"> <option value="business">Business</option> </Select> </Field></div>Props
PropTypeDefaultDescription
size"sm" | "md" | "lg"default: "md"Height 32 / 36 / 40px.placeholderstringdefault: —Greyed first option with value "", selected until the user picks.iconReactNodedefault: —Icon before the value.invalidbooleandefault: —Red border and aria-invalid. Set automatically by <Field error>.classNamestringdefault: —Classes for the outer box....propsSelectHTMLAttributesdefault: —Native attributes: value, defaultValue, onChange, name, required…
Accessibility
- A real <select>: arrow keys, type-ahead and the native picker on iOS and Android all work out of the box.
- Inside Field the label, hint and error are linked automatically; outside a Field, pass aria-label.
- The placeholder option is disabled, so it can't be chosen again once a value is picked; combine with required to block empty submits.
- The chevron and icon are decorative (aria-hidden) and don't intercept clicks.