Form
Field
Label, description and error around one control. It wires `id`, `aria-describedby`, `aria-invalid` and `aria-required` into the control, so every input in a form is announced correctly.
Shown in the sidebar and in invites.
Usage
- Do wrap every form control in a Field: it is the only way to get the label, description and error wired correctly.
- Do write errors that say how to fix the value ("Enter an email like name@company.com"), not just "Invalid".
- Do show errors after the person leaves the field or submits, not on every keystroke.
- Don’t use the placeholder as the label; use
hideLabelonly when the purpose is obvious. - Don’t put several controls in one Field; for a group of checkboxes use a fieldset with a legend.
- What works as the child: any Motion form control (TextInput, Textarea, SearchInput, NumberInput, Select, Combobox, Checkbox, Switch, RadioGroup, Slider, SegmentedControl, Calendar, DatePicker, DateRangePicker, FileUpload) or a native input / select / textarea, directly or inside a wrapper
<div>; the label finds it. - Don’t put a Menu (or a Popover with buttons) in a Field to pick a value: menus are for actions. Use Select for a short list and Combobox for a long or searchable one.
- For a custom control, pass
htmlForand give your control the sameid(or build it withuseFieldProps). In development, Field warns in the console when its label names no control.
Installation
Install the package (React 19):
Import the styles once, in your app entry or root layout:
Use it anywhere inside your app's <Theme> (see Installation):
Examples
Error
Passing error marks the control invalid (red ring, aria-invalid) and adds the message to its description. The message is announced politely when it appears.
We send the invite here.
Enter an email like name@company.com.
Any control
Every control in the package reads the Field. Other elements (a plain <input>, a third-party control) get the same props cloned in.
Billed monthly.
Hidden label
hideLabel keeps the label as the accessible name but hides it visually; use it only when the purpose is obvious from context.
Disabled
Contact an owner to change it.
Dark theme
Name is required.
API Reference
Field
A <div> (all its props are passed through). Adds:
| Prop | Type | Default |
|---|---|---|
label | ReactNode | |
description | ReactNode | |
error | ReactNode | |
required | boolean | false |
hideLabel | boolean | false |
disabled | boolean | false |
htmlFor | string | |
children | ReactNode |
Helpers
For building your own controls that work inside a Field.
| Prop | Type | Default |
|---|---|---|
useFieldProps(props) | (props) => props | |
useFieldControl() | FieldContextValue | null | |
fieldVariants | tv recipe |
Accessibility
- The
<label>points at the control (htmlFor); controls that aren’t labelable (slider thumbs, radio groups, date triggers) usearia-labelledbywith the label id instead. - Description and error are linked with
aria-describedby, in that order; the error id is only included while there is an error. - The error sits in an
aria-live="polite"region, so it is announced when it appears, without stealing focus. - The required asterisk is
aria-hidden; the control carriesaria-requiredinstead.