Accessible forms: labels, errors and the mistakes that fail WCAG

Published October 28, 2026 · about an 8-minute read

If I had to point at the single part of a website where accessibility most reliably falls apart, it's the forms. Not because forms are hard to make accessible — the rules are old and well understood — but because forms are where visual design fights hardest against assistive technology. The minimalist login with no visible labels, the error that's just a red outline, the custom dropdown a screen reader can't name. Here's how to build a form that actually passes, criterion by criterion.

Real labels, every time

The foundation is the humble <label>, programmatically tied to its input. WCAG covers this twice: 1.3.1 Info and Relationships (the association must be in the code, not just visual) and 3.3.2 Labels or Instructions (there must be a label or instruction at all). The clean way:

<label for="email">Email address</label>
<input type="email" id="email" name="email" autocomplete="email">

The for matches the input's id. Now a screen reader announces "Email address, edit text," and clicking the label focuses the field. You can also wrap the input inside the label, but the explicit for/id pairing is the one I reach for — it survives layout changes.

The number-one form failure I see, by a mile: using placeholder text as the only label. Placeholders vanish the moment someone types, they're typically low-contrast, and they aren't a reliable accessible name. A placeholder can show an example format alongside a real label. It can never be the label.

Errors that explain themselves

Validation is the next place forms break. Two criteria:

In practice I pair two things: a short error summary at the top of the form with links that jump focus to each bad field, and an inline message next to each field. Wire the inline message to the input with aria-describedby so a screen reader reads the error when the field gets focus:

<input id="email" aria-describedby="email-err" aria-invalid="true">
<p id="email-err">Enter a valid email, like name@example.com</p>

Custom controls need name, role and value

The moment you replace a native control with a styled <div> — a fancy dropdown, a toggle, a custom checkbox — you take on 4.1.2 Name, Role, Value yourself. Assistive tech has to be able to tell what the control is (role), what it's called (name), and what state it's in (value/checked/expanded). Native elements give you all of that free. A div gives you nothing until you add the ARIA roles, states and keyboard handling by hand — and that's a lot of easy-to-get-wrong work. My honest advice: use the native <select>, <input type="checkbox"> and real <button> elements unless you have a strong reason not to. The most accessible custom widget is usually the one you didn't build.

Help the browser help the user: autocomplete

1.3.5 Identify Input Purpose (Level AA) asks you to declare what common fields are for, using the autocomplete attribute — autocomplete="email", "name", "tel", "street-address" and so on. This lets browsers autofill correctly and helps people with cognitive disabilities who rely on that autofill, and it's a two-second addition. There's no reason to skip it on a signup or checkout form.

What WCAG 2.2 added for forms

The 2.2 update brought a few criteria that land squarely on forms:

CriterionWhat it means for your form
2.5.8 Target Size (Min) (AA)Interactive targets at least 24×24 CSS pixels (with some exceptions) — so checkboxes, radios and submit buttons aren't tiny tap targets.
3.3.7 Redundant Entry (A)Don't make people re-type information they already entered earlier in the same process — autofill it or let them pick it.
3.3.8 Accessible Authentication (AA)Don't gate login behind a cognitive test like a puzzle CAPTCHA or "memorize this code." Allow password managers and paste.

Test it the way a real user would

Here's the thing automated scanners can't fully do for forms: they'll catch a missing label or a color-only state, but they can't tell you the error message is confusing or the custom dropdown traps keyboard focus. So do the two-minute manual pass I do on every form:

Forms are also the part of a site that changes most — a new field, a redesign, a third-party form embed — so a form that passed last quarter can quietly regress. This is exactly what an accessibility audit plus ongoing monitoring is for.

Catch form accessibility issues automatically

Perimeter's accessibility check flags missing form labels, color-only states and other WCAG issues across your pages — alongside your TLS, headers and DNS posture — and re-checks on a schedule, so a new form that ships without labels gets caught before a user (or an auditor) hits it. Free, no signup.

Monitor your accessibility → · Compliance plan $49/mo · or run a free accessibility check