Form controls
The form primitives. Field owns the label/hint/error and wires accessibility onto its single
child control; the controls themselves stay native where possible (real keyboard + AT behavior).
Where the order routes
Notes are required
Wraps one control and wires id β label, aria-describedby (hint + error), and aria-invalid.
import { Field, Select } from '@repo/ui/form';
<Field label="Branch" hint="Where the order routes" error={errors.branch}> <Select value={branch} onChange={e => setBranch(e.target.value)}> <option value="hq">HQ</option> </Select></Field>| Prop | Type | Notes |
|---|---|---|
label | string | Rendered as the eyebrow-style <label htmlFor> |
hint | string | Helper text; hidden when error is set |
error | string | Sets aria-invalid + error styling on the child |
required | boolean | Adds the * marker |
id | string | Optional; auto-generated via useId otherwise |
Controls
Section titled βControlsβSelectβ styled native<select>with the brand chevron. All<select>props.Textareaβ styled native<textarea>. All<textarea>props.Checkbox/Radioβ native inputs tinted viaaccent-color; optional inlinelabel. Wrap radios inRadioGroup(role=radiogroup,orientation).Switchβrole=switchtoggle. Controlled:checked+onCheckedChange. Keyboard via the underlying button (space/enter).
import { Checkbox, RadioGroup, Radio, Switch } from '@repo/ui/form';
<Checkbox label="Mark as test order" checked={isTest} onChange={β¦} /><RadioGroup label="Tier" orientation="horizontal"> <Radio name="tier" value="1" label="Tier 1" /></RadioGroup><Switch checked={on} onCheckedChange={setOn} label="Email notifications" />Do / donβt
Section titled βDo / donβtβ- Do wrap every control in
Fieldso the label and error are wired for screen readers. - Do pass an accessible name to
Switch(label) β it has no text of its own. - Donβt use a
Switchfor choosing between options β thatβsRadioGroup. A switch is an immediate on/off. - Donβt hand-style raw
<input>s; reuse these so focus rings and error states stay consistent.
Accessibility
Section titled βAccessibilityβ- Native controls keep native keyboard + AT semantics;
Switchuses a real button withrole=switch+aria-checked. Focus-visible ring uses--om-orange-press(β₯3:1 on light). - Verified with
jest-axe(zero violations).