The composition component: label, control, and help or error copy, plus the wiring that binds them. Standalone fields keep their intrinsic rhythm; the aligned-row companion gives a pair of sibling fields shared natural-height label, control, and message tracks, then returns them to an ordinary stack below breakpoint.md.
The default is label and control alone, bound via for, on one space.2 gap. The caption line is opt-in: help when there is real context to add — never a repeat of the label, never load-bearing placeholder text — and the error takes its place while invalid.
Each ds-field-row aligns one pair through shared label, control, and natural message tracks. Missing copy leaves the message track empty; wrapping help or error expands it for both siblings, and the error icon stays on the first line. Below breakpoint.md, each pair stacks in source order.
Errors wire as a triple — aria-invalid on the control, an id on the message, aria-describedby pointing at it — and the whole block answers: the label joins the control's red via :has(), no extra wiring. The error replaces the help line and states the fix; type into the field to watch it clear.
Binary controls swap the label + control pair for a clickable row — the rows themselves are demoed with their components (see Checkbox and Radio). FormField adds the caption composition: a row needing help or error sits inside ds-field, wired with the same triple.
The field composes; the control keeps its own contract.
| Verdict | Rule |
|---|---|
| Do | Give every control a visible label via ds-field__label with for — aria-label substitutes only when the surrounding context is the label. |
| Do | Wire errors as the triple — aria-invalid on the control, an id on the message, aria-describedby pointing at it; the color change alone is never the signal. |
| Do | State the fix in the error (Enter a valid email address), not the failure — and let it replace the help line: one caption at a time. |
| Do | Label a radio or checkbox group with fieldset + legend — ds-field__label labels one control, a legend labels the group. |
| Do | Mark the optional fields ((optional)) when most are required, instead of starring every required one. |
| Do | Wrap each pair in ds-field-row when a multi-column form needs labels, controls, and variable-length messages to align. |
| Don’t | Repeat the label as help, or promote load-bearing placeholder text to a caption — help is optional context below the control. |
| Don’t | Stack a ds-field__label above a lone checkbox — binary controls take the row, the label wrapping the control and its text. |
| Don’t | Let the error icon carry the meaning — it is decorative (aria-hidden); the text is the message. |
| Don’t | Place independent ds-field boxes directly in a page grid or reserve a fixed caption height — both drift as help and errors wrap. |