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.

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.

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

<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:

  1. Validate on submit, not after every keystroke.
  2. Put the error in a <p> with role="alert" (or aria-live="polite") right after the field it describes.
  3. Point the field at the message with aria-describedby.
  4. Keep input aria-invalid="true" while the error is live.
  5. 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

Need a website built, fixed, optimised, migrated or replaced?

This technical resource is written by CSMBAC, a small design and development studio. If you would rather hand the problem to a professional, the website service page explains how we build enquiry-ready websites.

Explore website services