WCAG 2.2 Checklist: All 9 New Criteria + the Full AA List
WCAG 2.2 checklist: the 9 new success criteria explained, all 55 Level A and AA criteria in one table, what automation can test, and real failure data.
WCAG 2.2 became a W3C Recommendation in October 2023. It adds nine new success criteria to WCAG 2.1 and removes one (4.1.1 Parsing). To conform at Level AA you must meet all 55 Level A and AA criteria. Six of those are new: Focus Not Obscured (Minimum), Dragging Movements, Target Size (Minimum), Consistent Help, Redundant Entry and Accessible Authentication (Minimum).
Below: each new criterion with a pass/fail example and a test method, then all 55 A/AA criteria in one table, marked by what automation can check. Of the six new A/AA criteria, a standard automated engine fully tests only one.
We also measured two of the new criteria on real sites. 24.7% of 219 randomly sampled homepages failed Target Size (Minimum) in axe-core, and 34.6% of 208 homepages had at least one link or button completely hidden behind a sticky element while it had keyboard focus.
What Changed From WCAG 2.1 to 2.2
| Criterion | Level | In one sentence | Automated testing |
|---|---|---|---|
| 2.4.11 Focus Not Obscured (Minimum) | AA | A focused element must not be entirely hidden by author content | Scriptable (see below) |
| 2.4.12 Focus Not Obscured (Enhanced) | AAA | No part of the focused element may be hidden | Scriptable |
| 2.4.13 Focus Appearance | AAA | Focus indicator must be large and high-contrast enough | Partial |
| 2.5.7 Dragging Movements | AA | Anything done by dragging must also work with single clicks or taps | Manual |
| 2.5.8 Target Size (Minimum) | AA | Pointer targets at least 24Γ24 CSS px, or enough spacing | β
axe target-size |
| 3.2.6 Consistent Help | A | Help links or contact details appear in the same relative place on each page | Manual |
| 3.3.7 Redundant Entry | A | Don't make users re-type information they already gave in the same process | Manual |
| 3.3.8 Accessible Authentication (Minimum) | AA | No cognitive test (memorising, transcribing, puzzles) to log in, unless an alternative exists | Manual |
| 3.3.9 Accessible Authentication (Enhanced) | AAA | As 3.3.8, without the object-recognition exceptions | Manual |
| Removed: modern browsers and assistive tech no longer depend on it | β |
See the W3C's What's New in WCAG 2.2 and the full WCAG 2.2 Recommendation.
π‘ Backwards compatible: conforming to WCAG 2.2 AA also satisfies 2.1 AA, which most current laws and procurement rules still cite.
Tier 1 (P0): The Six New A/AA Criteria, One by One
2.5.8 Target Size (Minimum), AA
Every pointer target (link, button, form control) must be at least 24Γ24 CSS pixels. A smaller target still passes if a 24px-diameter circle centred on it doesn't overlap another target or that target's circle (the spacing exception). Links inside a sentence are exempt, as are targets whose size the browser controls and targets where the small size is essential.
/* β 16px social icons packed 4px apart: fails 2.5.8 */
.social a { width: 16px; height: 16px; margin-right: 4px; }
/* β
Visual icon stays 16px; the hit area grows to 24px+ */
.social a { display: inline-grid; place-items: center; min-width: 24px; min-height: 24px; }
.social a img { width: 16px; height: 16px; }In our sample, 54 of 219 homepages (24.7%) failed axe-core's target-size rule (1,038 elements), mostly social icons, carousel dots, banner close buttons and packed footer links. 24px is the AA minimum. The AAA criterion 2.5.5 and most touch guidelines recommend 44px.
2.4.11 Focus Not Obscured (Minimum), AA
When an element receives keyboard focus, it must not be completely hidden by content you added: sticky headers, cookie banners, chat launchers, "back to top" buttons. Partly covered still passes AA. Fully covered fails.
The classic failure needs Shift+Tab. Tabbing forward scrolls the next element in at the bottom of the viewport. Tabbing backward scrolls it in at the top, right under a sticky header.
/* β
Make the browser keep focused elements clear of a 72px sticky header */
html { scroll-padding-top: 80px; }
/* β
Same idea for a fixed bottom cookie bar */
html { scroll-padding-bottom: 96px; }scroll-padding keeps focused elements from landing underneath the bar. We tested this on 208 homepages with 40 Tab and 40 Shift+Tab presses each, without dismissing any banner. 72 (34.6%) had at least one focused element fully hidden. The covering element was a sticky header, nav bar or other fixed element on 48 homepages (23.1%), a cookie or consent banner on 21 (10.1%), and a pop-up modal on 13 (6.2%). We only counted cases where the covering element was itself fixed or sticky, so these figures are conservative.
2.5.7 Dragging Movements, AA
Sliders, sortable lists, map panning and kanban boards need a single-pointer alternative to dragging: buttons, a number input, or a "Move toβ¦" menu.
<!-- β
+/- buttons for users who can't drag precisely -->
<button type="button" aria-label="Decrease price">β</button>
<input type="range" min="0" max="500" step="10" aria-label="Maximum price">
<button type="button" aria-label="Increase price">+</button>3.2.6 Consistent Help, A
If you offer help (contact link, phone, chat, FAQ) on multiple pages, keep it in the same relative order each time, typically a fixed slot in the header or footer. You don't have to offer help, only be consistent when you do.
3.3.7 Redundant Entry, A
Within one process, don't make users type the same information twice; pre-fill it or offer reuse ("Billing address same as shipping"). Re-entry for security, like confirming a new password, is exempt.
3.3.8 Accessible Authentication (Minimum), AA
Logging in must not depend on a cognitive function test, such as remembering a password, transcribing a code or solving a puzzle, unless you provide an alternative or assistance. Two things practically guarantee a pass:
<!-- β
Let password managers and paste work: never block them -->
<input type="email" name="email" autocomplete="username">
<input type="password" name="password" autocomplete="current-password">
<!-- β onpaste="return false" on either field fails 3.3.8 -->Passkeys, magic links and "sign in with" providers also pass. Text-transcription CAPTCHAs fail without an alternative; object-recognition CAPTCHAs are allowed at AA but not AAA.
Tier 2 (P1): The Complete WCAG 2.2 Level A and AA Checklist
All 55 criteria you must meet for 2.2 AA. Auto means engines like axe-core have rules that can find failures, though passing them doesn't prove conformance. Partial means automation catches some failure types. Manual means a person has to test it.
| SC | Name | Level | Testing |
|---|---|---|---|
| 1.1.1 | Non-text Content | A | Partial |
| 1.2.1 | Audio-only and Video-only (Prerecorded) | A | Manual |
| 1.2.2 | Captions (Prerecorded) | A | Manual |
| 1.2.3 | Audio Description or Media Alternative | A | Manual |
| 1.2.4 | Captions (Live) | AA | Manual |
| 1.2.5 | Audio Description (Prerecorded) | AA | Manual |
| 1.3.1 | Info and Relationships | A | Partial |
| 1.3.2 | Meaningful Sequence | A | Manual |
| 1.3.3 | Sensory Characteristics | A | Manual |
| 1.3.4 | Orientation | AA | Manual |
| 1.3.5 | Identify Input Purpose | AA | Partial |
| 1.4.1 | Use of Color | A | Partial |
| 1.4.2 | Audio Control | A | Manual |
| 1.4.3 | Contrast (Minimum) | AA | Auto |
| 1.4.4 | Resize Text | AA | Partial |
| 1.4.5 | Images of Text | AA | Manual |
| 1.4.10 | Reflow | AA | Manual |
| 1.4.11 | Non-text Contrast | AA | Manual |
| 1.4.12 | Text Spacing | AA | Partial |
| 1.4.13 | Content on Hover or Focus | AA | Manual |
| 2.1.1 | Keyboard | A | Partial |
| 2.1.2 | No Keyboard Trap | A | Manual |
| 2.1.4 | Character Key Shortcuts | A | Manual |
| 2.2.1 | Timing Adjustable | A | Partial |
| 2.2.2 | Pause, Stop, Hide | A | Manual |
| 2.3.1 | Three Flashes or Below Threshold | A | Manual |
| 2.4.1 | Bypass Blocks | A | Partial |
| 2.4.2 | Page Titled | A | Partial |
| 2.4.3 | Focus Order | A | Manual |
| 2.4.4 | Link Purpose (In Context) | A | Partial |
| 2.4.5 | Multiple Ways | AA | Manual |
| 2.4.6 | Headings and Labels | AA | Manual |
| 2.4.7 | Focus Visible | AA | Manual |
| 2.4.11 | Focus Not Obscured (Minimum) β new | AA | Scriptable |
| 2.5.1 | Pointer Gestures | A | Manual |
| 2.5.2 | Pointer Cancellation | A | Manual |
| 2.5.3 | Label in Name | A | Manual |
| 2.5.4 | Motion Actuation | A | Manual |
| 2.5.7 | Dragging Movements β new | AA | Manual |
| 2.5.8 | Target Size (Minimum) β new | AA | Auto |
| 3.1.1 | Language of Page | A | Auto |
| 3.1.2 | Language of Parts | AA | Partial |
| 3.2.1 | On Focus | A | Manual |
| 3.2.2 | On Input | A | Manual |
| 3.2.3 | Consistent Navigation | AA | Manual |
| 3.2.4 | Consistent Identification | AA | Manual |
| 3.2.6 | Consistent Help β new | A | Manual |
| 3.3.1 | Error Identification | A | Manual |
| 3.3.2 | Labels or Instructions | A | Partial |
| 3.3.3 | Error Suggestion | AA | Manual |
| 3.3.4 | Error Prevention (Legal, Financial, Data) | AA | Manual |
| 3.3.7 | Redundant Entry β new | A | Manual |
| 3.3.8 | Accessible Authentication (Minimum) β new | AA | Manual |
| 4.1.2 | Name, Role, Value | A | Partial |
| 4.1.3 | Status Messages | AA | Manual |
Count the right-hand column and the gap is obvious: 3 criteria are Auto, 14 are Partial, 1 is Scriptable, and 37 (two-thirds) are Manual. Our guide to what automated accessibility testing catches and what it misses covers the full split rule by rule.
Tier 3 (P2): Where Real Sites Fail
The new criteria get the attention, but sites mostly fail the old ones. Across our 219 homepages, 87.7% failed at least one rule, led by color-contrast (64.4%), link-name (42.5%), image-alt and the new target-size (24.7% each). Fix those first. Our website accessibility statistics for 2026 have the full breakdown, and our walkthroughs on fixing color contrast errors and the most common WCAG violations cover the fixes.
Validation Protocol: Test the Two Scriptable 2.2 Criteria
This script checks 2.5.8 (with the spacing and inline-link exceptions) and 2.4.11 (tabbing forward and backward). It's the same test we ran on the sample above.
#!/usr/bin/env python3
"""WCAG 2.2 checks: SC 2.5.8 Target Size (24px or spacing exception; inline links exempt)
and SC 2.4.11 Focus Not Obscured (Tab + Shift+Tab, flag fully hidden focused elements).
Usage: pip install playwright && playwright install chromium
python3 wcag22_check.py https://example.com --tabs 60
"""
import argparse, asyncio
from playwright.async_api import async_playwright
TARGETS_JS = r"""() => {
const sel = 'a[href], button, input:not([type=hidden]), select, textarea, [role=button], [role=link], [role=checkbox], [role=tab], [onclick]';
const els = [...document.querySelectorAll(sel)].filter(el => {
const r = el.getBoundingClientRect(), s = getComputedStyle(el);
return r.width > 1 && r.height > 1 && s.visibility !== 'hidden' && s.display !== 'none';
});
const inline = el => { // exception: link inside a sentence of text
if (el.tagName !== 'A') return false;
const p = el.parentElement; if (!p) return false;
const txt = (p.innerText || '').replace((el.innerText || ''), '').trim();
return getComputedStyle(el).display === 'inline' && txt.length > 20;
};
const rects = els.map(el => el.getBoundingClientRect());
const fails = [];
els.forEach((el, i) => {
const r = rects[i];
if (r.width >= 24 && r.height >= 24) return;
if (inline(el)) return;
const cx = r.left + r.width / 2, cy = r.top + r.height / 2;
// spacing exception: 24px circle (radius 12) must not intersect another target's rect
const crowded = rects.some((o, j) => {
if (j === i) return false;
const nx = Math.max(o.left, Math.min(cx, o.right)), ny = Math.max(o.top, Math.min(cy, o.bottom));
return Math.hypot(cx - nx, cy - ny) < 12;
});
if (crowded) fails.push({tag: el.tagName.toLowerCase(), w: Math.round(r.width), h: Math.round(r.height),
label: (el.getAttribute('aria-label') || el.innerText || el.getAttribute('title') || '').trim().slice(0, 40)});
});
return {checked: els.length, fails};
}"""
OBSCURED_JS = r"""() => {
const el = document.activeElement;
if (!el || el === document.body) return null;
const r = el.getBoundingClientRect();
if (r.width === 0 || r.height === 0) return null;
const pts = [[r.left + 2, r.top + 2], [r.right - 2, r.top + 2], [r.left + 2, r.bottom - 2],
[r.right - 2, r.bottom - 2], [r.left + r.width / 2, r.top + r.height / 2]]
.filter(([x, y]) => x >= 0 && y >= 0 && x < innerWidth && y < innerHeight);
if (!pts.length) return null; // off-screen: browser will scroll it
const covered = pts.every(([x, y]) => { const hit = document.elementFromPoint(x, y);
return hit && hit !== el && !el.contains(hit) && !hit.contains(el); });
if (!covered) return null;
const cover = document.elementFromPoint(pts[0][0], pts[0][1]);
const fixed = cover && cover.closest('*') && [...function* (n) { while (n) { yield n; n = n.parentElement; } }(cover)]
.find(n => ['fixed', 'sticky'].includes(getComputedStyle(n).position));
return {focused: (el.getAttribute('aria-label') || el.innerText || el.tagName).trim().slice(0, 40),
coveredBy: fixed ? (fixed.id ? '#' + fixed.id : [fixed.tagName.toLowerCase(), ...[...fixed.classList].slice(0, 2)].join('.')) : 'unknown'};
}"""
async def main(url, tabs):
async with async_playwright() as pw:
browser = await pw.chromium.launch()
page = await browser.new_page(viewport={"width": 1366, "height": 768})
await page.goto(url, wait_until="load")
await page.wait_for_timeout(2000)
t = await page.evaluate(TARGETS_JS)
print(f"SC 2.5.8 Target Size: {len(t['fails'])} failing of {t['checked']} visible targets")
for f in t["fails"][:25]:
print(f" {f['tag']:6} {f['w']}x{f['h']}px \"{f['label']}\"")
hidden = []
await page.evaluate("document.activeElement && document.activeElement.blur()")
# Forward, then backward: Shift+Tab scrolls elements in at the TOP edge,
# which is exactly where sticky headers sit.
for key in ["Tab"] * tabs + ["Shift+Tab"] * tabs:
await page.keyboard.press(key)
await page.wait_for_timeout(120)
try:
hit = await page.evaluate(OBSCURED_JS)
except Exception: # focus moved into something that navigated
break
if hit and hit not in hidden:
hidden.append(hit)
print(f"\nSC 2.4.11 Focus Not Obscured: {len(hidden)} element(s) fully hidden while focused ({tabs} Tab + {tabs} Shift+Tab)")
for h in hidden:
print(f" \"{h['focused']}\" hidden by {h['coveredBy']}")
await browser.close()
if __name__ == "__main__":
ap = argparse.ArgumentParser()
ap.add_argument("url")
ap.add_argument("--tabs", type=int, default=60)
a = ap.parse_args()
asyncio.run(main(a.url, a.tabs))Output on a test page with a fixed 120px header and two 16px icon links:
SC 2.5.8 Target Size: 2 failing of 5 visible targets
a 16x16px ""
a 16x16px ""
SC 2.4.11 Focus Not Obscured: 1 element(s) fully hidden while focused (8 Tab + 8 Shift+Tab)
"Link one" hidden by headerThe inline link in the first paragraph was correctly exempt, and only the Shift+Tab pass exposed the hidden link.
How BugViso Checks WCAG 2.2 Automatically
BugViso runs a self-hosted axe-core engine on every audited page with the wcag2a, wcag2aa, wcag21a, wcag21aa and wcag22aa rule tags. 2.2's Target Size (Minimum) is therefore tested alongside the full 2.1 A/AA rule set, in a real Chromium render after scripts and lazy content have loaded.
The mobile device-emulation pass measures tap targets against the WCAG 2.5.8 24Γ24 px minimum and reports smaller 44px recommended targets separately as guidance, not failures. It also flags horizontal overflow and viewport problems. Each violation in the report names the rule, the WCAG criterion, the impact level and the failing elements, and the same data goes into the PDF report.
BugViso doesn't replace manual testing for the criteria marked Manual above, such as consistent help, redundant entry and authentication flows. Run a free BugViso accessibility scan to cover the automatable part in a minute.
High-Risk Oversights
- Testing only with Tab. Focus Not Obscured failures usually appear with Shift+Tab, and with cookie banners still open.
- Assuming 24px means "make everything 24px". A 16px icon with enough clear space passes under the spacing exception.
- Blocking paste on login or "confirm email" fields. This breaks password managers and fails 3.3.8.
- Treating overlays as 2.2 compliance. They don't change your default rendering, so they can't fix target size, focus obscuring or login flows.
FAQ
Is WCAG 2.2 legally required?
It depends on the jurisdiction. Many regulations and procurement standards still reference WCAG 2.1 AA. Because 2.2 is backwards compatible, conforming to 2.2 AA satisfies a 2.1 AA requirement too. Check the exact standard your law or contract cites, and get legal advice for compliance decisions.
How many success criteria are in WCAG 2.2 Level AA?
55: 31 at Level A and 24 at Level AA. That's the 50 A/AA criteria from WCAG 2.1, plus the six new A/AA criteria, minus the removed 4.1.1 Parsing.
Was anything removed in WCAG 2.2?
Yes. 4.1.1 Parsing is obsolete, because browsers now parse HTML consistently and malformed markup no longer breaks assistive technology by itself.
Can an automated tool make my site WCAG 2.2 compliant?
No. Automated tools find a meaningful share of failures, especially contrast, names, alt text and target size, but two-thirds of the 55 criteria need a human to evaluate. Use automation to clear the bulk, then test manually with keyboard and screen reader.
Conclusion
WCAG 2.2 adds six A/AA criteria, but real sites mostly still fail the old ones, so clear contrast, names and alt text first, then script the two new criteria you can test (target size and focus obscuring) and hand the rest to manual review, starting with a free BugViso WCAG scan.
See where your site stands
Run a free BugViso audit for SEO, speed, accessibility and AI search readiness β with fixes you can ship today.