Skip to main content

Search rules

Search all UI Guides rules by name, category, or source

forms@Ibelick

Link Errors to Fields Programmatically

MUST

MUST: An invalid field must set `aria-invalid="true"` and point `aria-describedby` at its message. `aria-describedby` takes a space-separated LIST of ids — keep BOTH the persistent hint id and the error id; overwriting the hint with the error on validation is the common bug, and it makes the field stop explaining itself the moment it goes wrong. Orthogonal to `forms-ibelick-error-placement` (which governs WHERE the message sits): a well-placed error that is not associated still fails.

An error is not an error until the field points at it: set aria-invalid on the input and list the error and helper text ids in aria-describedby

<input id="email" aria-invalid={!!err} aria-describedby={err ? "email-err email-hint" : "email-hint"} />
<p id="email-err">Enter a valid email address</p>
<p id="email-hint">We only email you about your account</p>

Bad

Good

Why it matters

From the forms and errors rules in ibelick's fixing-accessibility skill. This is the rule that red text alone cannot satisfy. `<input id="email" /><span>Invalid email</span>` renders a perfectly visible error and communicates nothing to the accessibility tree: the input still computes as valid, its accessible description is empty, and a screen-reader user who tabs back to the field to fix it hears the label and nothing else.

Two attributes close the gap. `aria-invalid="true"` flips the field's computed state, so the error is announced as a property of the control rather than as loose text somewhere on the page. `aria-describedby` attaches the message — and it takes a space-separated LIST of ids, which is the detail people get wrong. A field usually has two things to say: a persistent hint ("We only email you about your account") and a transient error.

The common bug is to overwrite the hint id with the error id on validation, so the moment the field goes invalid the user stops hearing why it exists. Keep both: `aria-describedby="email-err email-hint"`. This is orthogonal to forms-ibelick-error-placement, which governs WHERE the message sits visually ("where the action happens"); this one governs whether the message is LINKED to the control at all, wherever it sits. A correctly placed error that is not associated still fails, and an associated error still needs to be placed well.

Built by Gleb Stroganov, design engineer at Evil Martians.

The rules come from other people's skills and guidelines — Vercel, Rauno Freiberg, @Ibelick, impeccable, Emil Kowalski, Tailwind, RAMS — each one credited on the Sources page. The work here is extraction and wiring: every rule is pulled into one corpus, given a good and a bad example you can operate, a MUST/SHOULD/NEVER rule an agent can paste, and a link back to where it came from.