November 16, 2021 · reala11y team
Accessible forms in WordPress: labels, errors, instructions
Build accessible WordPress forms: visible labels, programmatic association, clear errors and instructions. A practical, honest guide to WCAG 3.3.2 and 3.3.1.
Forms are where accessibility quietly breaks. A site can have clean headings, good contrast, and useful alt text, then hand a screen-reader user a checkout form whose fields announce as “edit text, blank.” The user has no idea what to type. They abandon the form, and you never see why.
Two WCAG 2.2 success criteria govern most of this: 3.3.2 Labels or Instructions (every input needs a clear label or instruction) and 3.3.1 Error Identification (when input fails, say what went wrong, in text). Both are Level A. Both are very common, and both are fixable in code.
Visible labels, not placeholders
The single most frequent form mistake is using placeholder text as the label:
<input type="email" placeholder="Email address">
Placeholders vanish the moment someone starts typing, fail contrast requirements in most themes, and are not reliably announced by assistive technology. Once the field has a value, the user has no on-screen reminder of what it holds.
Use a real, visible <label> instead:
<label for="email">Email address</label>
<input type="email" id="email" name="email">
A placeholder can still offer a format hint (“[email protected]”), but it is never a substitute for the label.
Program the association, don’t just place it nearby
Sighted users connect a label to a field by proximity. Assistive technology needs the connection in the markup. There are two reliable ways:
- Explicit:
<label for="email">paired with<input id="email">. Theforandidmust match exactly. - Implicit: wrap the input inside the label —
<label>Email <input type="email"></label>.
When a control genuinely can’t take a visible label (an icon-only search button, say), aria-label or aria-labelledby carries the accessible name. Prefer a visible label whenever the layout allows it; a label everyone can see helps users with cognitive and motor differences too, not only screen-reader users.
This is one of the spots where WordPress itself trips up. Plugin-generated search widgets, comment forms, and contact forms often emit an input with no associated label at all. The fix is small and structural, which is exactly the kind of issue reala11y identifies and remediates at the code level — by correcting the underlying HTML, not by layering a widget over it.
Instructions belong before the input
If a field has rules — a password length, a required format, an accepted file type — say so before the user reaches it, not only after they get it wrong.
<label for="pwd">Password</label>
<p id="pwd-hint">At least 12 characters, including one number.</p>
<input type="password" id="pwd" aria-describedby="pwd-hint">
aria-describedby ties the hint to the field so it’s announced along with the label. Mark required fields in text or with a programmatically exposed required attribute — never with colour or an unexplained asterisk alone.
Errors a person can actually act on
WCAG 3.3.1 asks that when an entry is rejected, the error is identified in text and the user is told which field failed and why. That rules out the patterns everyone has suffered:
- A red border with no message.
- A generic “submission failed” with no field named.
- An error shown only by colour.
A solid error pattern does three things:
- Names the field and the problem in text: “Email address: enter a valid address like [email protected].”
- Associates the message with its field via
aria-describedby, and setsaria-invalid="true"on the input. - Announces dynamically — for client-side validation, put errors in a container with
role="alert"(oraria-live="assertive") so they’re read out without the user hunting for them.
Move focus to the first invalid field, or to a summary at the top of the form that links to each error. That keeps keyboard and screen-reader users oriented instead of lost.
Test it the way real users do
Automated scanning catches a meaningful share of form problems — missing labels, empty buttons, mismatched for/id — but it can’t judge whether your label text is meaningful or your error message is useful. So pair the two:
- Run a scanner to catch the structural failures fast.
- Then tab through the form with the mouse untouched, and listen to it with a screen reader (NVDA on Windows, VoiceOver on Mac). Confirm every field announces a name, every hint is read, and every error is spoken.
For the full criteria — including what changed in WCAG 2.2 (a W3C Recommendation since 5 October 2023) — see our WCAG 2.2 guide.
The honest takeaway
Accessible forms are mostly unglamorous code hygiene: a real label, a matching id, a hint in the right place, an error message that says what to fix. None of it requires an overlay or a magic button. Automated tools, including reala11y, typically surface 30–40% of WCAG issues by criteria and help your site move toward WCAG 2.2 AA conformance — the remaining judgment calls still need a human at the keyboard. Fix the markup, then go listen to your own form. That last step is where the real bugs show up.