Input
Examples
Input fields
Input sizes
Disabled state
Required and optional
Mark the required side with a Required badge on the label, and say
"Optional" in a FieldDescription — never an
asterisk, which carries no meaning to a screen reader on its own. Pick one per
form and stay with it: if most fields are required, label the few optional ones
instead of badging everything.
required on the control itself is separate — it drives native validation and
aria-required, and should be set whether or not the badge is shown.
Invalid state
aria-invalid paints the halo on the control. The message itself is a
FieldError, which tucks behind the control so the
two read as one shape — never an InlinePrompt,
which is a standalone status pill, not field validation.
Valid state
The mirror of the invalid state, in green. data-valid is a data attribute
rather than an ARIA one because ARIA has no affirmative counterpart to
aria-invalid — there is nothing to announce until there is a message to
announce.
It comes at two volumes, and the quiet one is the default. data-valid="quiet"
is a tick at the trailing edge of the control and nothing else: no halo, no
border, no panel, no reflow. Several fields can carry it at once without the form
reading as a wall of green, which is exactly what makes it the one to reach for
after a format check or a lookup that simply came back fine.
data-valid="true" is the loud one: the full halo, plus a
FieldSuccess that tucks behind the control the way a
FieldError does and announces politely (role="status"). Spend it on the one
answer worth a sentence — username free, code accepted, address found. Spend it
twice on the same form and you have spent it nowhere, and a wall of green is as
hard to scan as a wall of red.