Field · Input Atom
Field owns the wiring that is most often silently wrong: the label pointing at the control, the
hint and error being announced through aria-describedby, and aria-invalid matching the visible
error state. It owns nothing else — no validation, no form state.
Usage
We only use this for receipts.
<Field label="Work email" hint="We only use this for receipts."><Input type="email" name="email" placeholder="you@company.com" /></Field>Errors
A string renders the message and marks the control invalid. error as a bare true marks it
invalid without a message — for the case where the message lives somewhere else on the page.
We only use this for receipts.
That address is already registered.
<Field label="Work email" hint="We only use this for receipts." error="That address is already registered."><Input type="email" defaultValue="ada@company.com" /></Field>Do
Write the error as what to do next: 'That address is already registered.'
Don't
Write 'Invalid input' — it passes the aria wiring and still tells the person nothing.
With a form library
The library is deliberately neutral. Nothing below is an adapter; Input simply forwards its
ref and props.
Same component, three different form stories.
// react-hook-form<Field label="Email" error={errors.email?.message}><Input {...register('email')} /></Field>
// Next Server Action — no client form state at all<form action={createUser}><Field label="Email"><Input name="email" required /></Field></form>Props
| Prop | Type | Default | Notes |
|---|---|---|---|
| label | ReactNode | — | Required. Use labelHidden rather than dropping it. |
| hint | ReactNode | — | Guidance shown before the person makes a mistake. |
| error | ReactNode | true | — | A message, or true for invalid-without-message. |
| required | boolean | false | Marks the label and forwards required to the control. |
| labelHidden | boolean | false | Visually hidden, still announced. |
Accessibility notes
- The error is rendered with
role="alert", so it is announced when it appears. aria-describedbylists hint and error in reading order, not just the last one.- A
Inputused outside aFieldstays unwired rather than inventing ids — passaria-label.