TL;DR: WCAG 2.2 kept every form requirement from 2.1 and added three new ones — redundant entry, accessible authentication, and a minimum target size. Most forms marked "accessible" still fail on the basics: placeholder-as-label, color-only error states, and focus styles stripped with outline: none. This is a working checklist, not a theory lecture.
Here's the part that trips up even careful teams: the new 2.2 criteria aren't exotic edge cases. They catch patterns that are common in production forms right now — re-typing a shipping address you already collected at checkout, a CAPTCHA with no non-visual alternative, a checkbox rendered at 16×16 pixels. Studios that build accessible, standards-compliant software write these checks into the definition of done, not into a pre-launch audit — because retrofitting a form's markup after launch is far more expensive than getting the label association right the first time.
This checklist covers what actually breaks: labels, error messages, keyboard and focus behavior, the three criteria new to WCAG 2.2, the autocomplete attribute nobody remembers, a compact table you can run against any form, and how to test all of it without pretending a scanner is a substitute for a keyboard.
Almost every production form survives visually and fails structurally. The most common culprit is the placeholder-as-label trap: a gray hint sitting inside the input, doing the visual job of a label while providing none of its semantics. The moment a user starts typing, the placeholder vanishes — and if the form was never given a real <label>, a screen reader has nothing to announce when focus lands on that field. The field looks finished. It is not done.
The pattern repeats across the rest of the form: errors flagged only by a red border, focus rings removed for aesthetics and never replaced, and now, under WCAG 2.2, three additional failure modes that didn't exist as testable criteria before this version of the spec. None of this requires a redesign. It requires checking the markup against what the spec actually says, field by field.
Success Criterion 1.3.1 (Info and Relationships) and 3.3.2 (Labels or Instructions) both come down to the same requirement: every input needs a programmatically associated label, and anything the user must know to fill the field correctly — format, units, required status — needs to be exposed in text, not implied by placement or color.
<!-- Bad: placeholder is not a label. Gone on focus, never exposed by name to AT. -->
<input type="email" placeholder="Email address">
<!-- Good: explicit label, persists, and announces correctly -->
<label for="email">Email address</label>
<input type="email" id="email" name="email" autocomplete="email">A placeholder can still supplement a label with a format hint ("[email protected]"), but it can never replace one. If you're using aria-label instead of a visible label purely to save layout space, check whether that's actually necessary — a visually hidden label (class="sr-only" or equivalent, not display: none) keeps both the visible design and the accessible name.
3.3.1 (Error Identification) requires that an error be described in text, identifying which field it belongs to. 3.3.3 (Error Suggestion) goes further: if you know how to fix it, say so. A red outline alone satisfies neither — it fails users who can't perceive color differences and it fails every screen reader user outright, because color carries no semantic signal.
<!-- Bad: color-only, no text, no field association -->
<input type="password" id="pw" style="border-color:red">
<!-- Good: field-specific text, programmatically tied to the input -->
<label for="pw">Password</label>
<input type="password" id="pw" aria-describedby="pw-err" aria-invalid="true">
<p id="pw-err" role="alert">Password must be at least 12 characters.</p>aria-describedby ties the error text to the field so a screen reader announces it alongside the label when focus lands there. role="alert" (or a live region) tells assistive tech to announce new errors without the user having to go looking for them.
2.4.3 (Focus Order) requires that tabbing through a form follow a sequence that makes sense — visually and logically, not whatever order the DOM happens to fall in after a flexbox reorder. WCAG 2.2 adds two more: 2.4.11 (Focus Not Obscured, Minimum) says a sticky header or cookie banner can't fully hide the focused element, and 2.4.13 (Focus Appearance) sets a minimum size and contrast for the focus indicator itself — not just "something visible," but a specific area and contrast ratio against the unfocused state.
/* Bad: removes the indicator and replaces it with nothing */
input:focus { outline: none; }
/* Good: a focus ring that meets the 2.4.13 area and contrast minimums */
input:focus-visible {
outline: 2px solid #0098f2;
outline-offset: 2px;
}If a design system removed outline site-wide at some point for aesthetics, that single rule is usually the single largest source of 2.4.13 failures on a given form. Don't remove a focus style without shipping a replacement in the same commit.
These three criteria are the actual delta between 2.1 and 2.2, and they're the ones a 2.1-era checklist won't catch.
If a user already gave you a piece of information earlier in the same process, don't make them type it again from memory — unless re-entry is essential (confirming a password, for example). A multi-step checkout that asks for a shipping address, then asks again for billing without an autofill or "same as shipping" option, fails 3.3.7. The fix is usually a checkbox, not a redesign.
<input type="checkbox" id="same-addr" checked>
<label for="same-addr">Billing address is the same as shipping</label>
<!-- When checked, populate and hide/disable the billing fields -->A login or signup flow can't rely solely on a "cognitive function test" — solving a puzzle, transcribing distorted characters, remembering a password with no paste or password-manager support — unless an alternative method exists that doesn't. A visual CAPTCHA without an audio or non-puzzle alternative fails this criterion outright. The exceptions are narrow: tests that verify a specific object (like recognizing your own uploaded photo) or ones with an accessible alternative method already in place are permitted.
In practice this mostly means: don't block password paste, offer a non-puzzle verification path (email magic link, WebAuthn, or an audio CAPTCHA alongside the visual one), and never make solving a visual puzzle the only way in.
Interactive targets — checkboxes, radio buttons, small icon buttons inside a form — need at least 24×24 CSS pixels of space, unless there's enough spacing around a smaller target to give it an equivalent effective area, or it's inline within a sentence.
/* Bad: a 16px checkbox with no extra hit area */
input[type="checkbox"] { width: 16px; height: 16px; }
/* Good: visual size can stay small; the hit area meets 24x24 */
input[type="checkbox"] {
width: 16px;
height: 16px;
padding: 4px;
box-sizing: content-box; /* adds 8px total, bringing the target to 24x24 */
}1.3.5 (Identify Input Purpose) is from WCAG 2.1, but it's the most commonly skipped line in a form's markup. The autocomplete attribute isn't a browser nicety — for users of screen readers, switch access, and speech input, it lets assistive technology identify the purpose of a field and fill it correctly, which is often faster than typing at all.
<input type="email" id="email" name="email" autocomplete="email">
<input type="tel" id="phone" name="phone" autocomplete="tel">
<input type="text" id="given-name" name="given-name" autocomplete="given-name">
<input type="text" id="postal" name="postal-code" autocomplete="postal-code">The MDN autocomplete reference lists the full set of recognized values. If a field maps to a standard personal-data category and doesn't have one of these tokens, that's a quick, mechanical fix — no design discussion required.
| Criterion | Level | What to check |
|---|---|---|
| 1.3.1 Info and Relationships | A | Every input has a programmatically associated label (not just visual proximity) |
| 1.3.5 Identify Input Purpose | AA | autocomplete set on fields that map to a standard personal-data category |
| 3.3.2 Labels or Instructions | A | Required fields, format, and units stated in text, not color or placeholder alone |
| 3.3.1 Error Identification | A | Errors named in text and tied to the specific field that failed |
| 3.3.3 Error Suggestion | AA | Where the fix is knowable, the error text says what to do |
| 2.4.3 Focus Order | A | Tab order matches visual and logical reading order |
| 2.4.11 Focus Not Obscured (Minimum) | AA | Sticky headers/banners never fully hide the focused element |
| 2.4.13 Focus Appearance | AAA* | Focus indicator meets minimum area and contrast, not just "visible" |
| 3.3.7 Redundant Entry | A | Previously entered data is reused (autofill, "same as") instead of re-typed |
| 3.3.8 Accessible Authentication (Minimum) | AA | No step requires solving a cognitive puzzle with zero alternative |
| 2.5.8 Target Size (Minimum) | AA | Interactive controls have at least a 24×24 CSS px target |
*2.4.13 is formally AAA, but most teams treat it as a practical AA bar since the common failure (no replacement after outline: none) also tends to fail other A/AA criteria around visibility.
A scanner is a starting point, not a verdict. Automated tools like axe or Lighthouse's accessibility pass catch missing labels, insufficient contrast, and missing alt text reliably — these are the mechanical checks. They cannot tell you whether your error text makes sense, whether the tab order matches the visual layout, or whether a screen reader user can actually complete the form.
A minimal manual pass before anything ships: unplug the mouse and tab through the entire form, checking that focus order matches the visual order and that every stop has a visible indicator. Then run it once with a screen reader — VoiceOver on macOS or NVDA on Windows, both free — and confirm every label and error is announced at the right moment. That combination catches what a scanner structurally cannot see: whether the experience, not just the markup, actually works.
No. WCAG 2.2 is backward compatible — every 2.1 success criterion still applies, and 2.2 adds nine new ones (three of which are specific to forms, covered above). A page conformant to 2.2 is automatically conformant to 2.1; a 2.1-only page may still fail the new criteria.
Not as a replacement. It's fine as a supplementary format hint shown alongside a real <label>, but on its own it fails 3.3.2 and 1.3.1: it disappears on input, has no guaranteed contrast, and isn't reliably exposed as the field's accessible name.
24×24 CSS pixels under 2.5.8, with exceptions for inline targets (links within a sentence), targets with enough surrounding spacing to give an equivalent effective area, and cases where the small size is essential to the function.
Not necessarily a redesign — but you do need an alternative path that doesn't require solving a cognitive puzzle, such as an audio CAPTCHA, email verification, or WebAuthn. A visual-puzzle-only CAPTCHA with zero alternative fails 3.3.8.
No. It reliably catches missing labels, contrast failures, and missing alt text, but it cannot evaluate whether error text is actually useful, whether focus order makes sense, or whether a screen reader user can complete the task. Treat it as a first pass, not a conformance test.
AA is the level referenced by nearly every legal and procurement accessibility requirement (including the ADA-adjacent standards most commercial sites target), and it's what this checklist is built around. AAA includes a smaller set of criteria that are valuable but not expected site-wide — 2.4.13 is one of the few AAA items worth adopting broadly because its failure mode overlaps with AA problems anyway.
Any information the user already provided earlier in the same multi-step process — a previous page, a previous session step, or data the system already has (like a logged-in user's saved address). Re-asking for it without an autofill, copy, or "same as" option fails 3.3.7 unless re-entry serves a real purpose, like re-confirming a password.