Reference guide · html-css-js · Published 2026-08-15 · 4 min read
Accessible forms: labels, focus and feedback
Build accessible forms that humans and screen readers can use: label for, fieldset legend, autocomplete and clear errors.
- ·Label every field
- ·Group and assist
- ·Errors and focus
Labels are the whole game
The single biggest form accessibility problem is an input with no label. Placeholder text is not a label: it disappears the moment the user types, it is invisible to some screen readers, and in some browsers it renders the same low contrast colour as a hint. Serve the same role with a real label.
Explicit labels use for and id to connect the words to the field:
<label for="email">Email address</label>
<input type="email" id="email" name="email" autocomplete="email">
The for and id pair means a mouse user who clicks the label focuses the input, a screen reader announces the label when the field is reached, and the association survives any page rearrangement. Wrapping the input inside the label element also works, but the explicit pair is easier to keep correct across templates and themes.
Group related fields with fieldset and legend
Radio groups, checkboxes and date parts need a group heading, which is exactly what <fieldset> and <legend> provide. The legend names the group, and screen readers announce the legend before each option, which answers the "one of these" context.
<fieldset>
<legend>Contact preference</legend>
<label><input type="radio" name="contact" value="email"> Email</label>
<label><input type="radio" name="contact" value="phone"> Phone</label>
</fieldset>
Autocomplete hides nothing
autocomplete is not a privacy leak, it is a requirement for users who rely on their browser to fill forms: names, addresses, emails, country codes. Add it for every field where the browser knows the concept. WCAG success criterion 1.3.5 asks for it at Level AA, and the non-logged-in checkout form is the classic case, where the saved address or card data only matches when the field names line up.
The field anatomy that helps both humans and screen readers
- Use the exact
typefor input:email,tel,number,url,search, so the mobile keyboard matches. - Keep the visible label next to the field it describes, either the standard above-field arrangement or a floated position that never overlaps.
- Give the field a
nameandid; both are cheap and the id is what label links to. - Use
aria-describedbyto connect helper text and error text to the field.
<label for="pass">Password</label>
<input type="password" id="pass" name="pass" autocomplete="new-password"
aria-describedby="pass-hint pass-error">
<p id="pass-hint">Eight characters or more.</p>
<p id="pass-error" role="alert"></p>
Error messages that arrive on time
Error text must be close to the field, show up after validation, be announced to the screen reader, and not rely on colour alone. The pattern:
- Validate on submit, not after every keystroke.
- Put the error in a
<p>withrole="alert"(oraria-live="polite") right after the field it describes. - Point the field at the message with
aria-describedby. - Keep input
aria-invalid="true"while the error is live. - Move keyboard focus to the first invalid field so a screen reader user hears the problem next.
Focus and visibility
The removal of focus outlines is the most common way design tables break forms. The :focus-visible pseudo-class gives you the best of both: keep the visible outline for keyboard users, let pointer users keep the button clean.
:focus-visible {
outline: 2px solid #1c6ef2;
outline-offset: 2px;
}
Focusable fields must also be visible when focused, a contrast check that some designers miss by setting the background to the focus color only. Text in the field needs a readable contrast ratio against the focus background, which the accessibility CSS and JS route covers.
Prevention
- Never delete the label when the design feels minimal; move it or style it, but keep it in the DOM, screen reader users need it.
- Keep a label for every field; when space is truly tight, a placeholder or
aria-hiddenhint is a fallback, not the primary label, and the visible helper must still announce the field purpose. - Test the form with the keyboard only, Tab from the top, and with a screen reader once, the Tab order and the announced label are the two things that matter most.
- The form still needs the semantic structure of the page, covered in semantic HTML, and any custom component that replaces a native input must take on the native role and keyboard behaviour by hand, which is where the accessibility and JS article picks up.