Skip to main content

Compliance & Lawsuits

WCAG 2.2 AA Checklist with Code Examples

Last updated

WCAG 2.2 is the current W3C Recommendation for web accessibility. Published in October 2023, it adds 9 new success criteria on top of WCAG 2.1 and removes one legacy criterion (4.1.1 Parsing). For most small and mid-size sites, the practical Level AA delta is five new requirements: target size, focus appearance, focus not being obscured, redundant entry, and accessible authentication. This page walks through each new criterion with a plain-English summary, working code, a note on what your automated scanner can and cannot catch, and a manual test step you can run today. We do not promise “WCAG 2.2 AA compliant” outcomes — we use the W3C terms conformance, passes, and meets. Conformance is an evidence claim you make about a specific page on a specific date, not a permanent attribute of a site.

Per Deque's Automated Accessibility Coverage Report, Deque reported automated tests identified 57.38% of issue instances by volume in its dataset — based on 2,000+ audits across 13,000+ pages and ~300K issues. That number frames everything below: automation is an excellent first pass, but several of the new WCAG 2.2 criteria (notably dragging movements and consistent help) need a human in the loop. See What Scanners Miss for the long version.

The W3C also publishes a What's New in WCAG 2.2 page with persona examples motivating each new criterion — a shopper with a tremor who cannot drag a slider, a user with low vision and an extended keyboard who keeps losing focus behind a sticky bar, a user with cognitive disabilities who can't memorize a security question. The rest of this page treats those personas as the audience you are actually building for, not as edge cases.

What changed from WCAG 2.1 to 2.2

WCAG 2.2 is backwards-compatible with 2.1 in the sense that every 2.1 success criterion is preserved except 4.1.1 Parsing, which was removed. The W3C What's New in WCAG 2.2 page is the authoritative summary — including the persona examples used to motivate the new criteria (a user with low vision using zoom, a user with a tremor, a user with cognitive disabilities, and so on). The additions, by level:

Level AA (the ones you have to ship)

  • 2.4.11 Focus Not Obscured (Minimum) — the focused element must not be entirely hidden by author-created content (sticky bars, cookie banners, chat widgets).
  • 2.5.7 Dragging Movements — any drag interaction needs a single-pointer alternative (click, tap, or keyboard).
  • 2.5.8 Target Size (Minimum) — interactive targets at least 24×24 CSS pixels, with documented exceptions.
  • 3.3.8 Accessible Authentication (Minimum) — no cognitive function test required to log in (no transcribed CAPTCHAs, no “remember this 12-digit code”).

Level A (already required at the lowest conformance level)

  • 3.2.6 Consistent Help — help mechanisms (chat, phone, contact link) appear in the same relative order across pages where they are present.
  • 3.3.7 Redundant Entry — information already provided in the same process is auto-filled or selectable.

Level AAA (optional for most compliance targets)

  • 2.4.12 Focus Not Obscured (Enhanced) — no part of the focused element is hidden.
  • 2.4.13 Focus Appearance — focus indicator meets a defined minimum area and contrast against the unfocused state.
  • 3.3.9 Accessible Authentication (Enhanced) — no object or image recognition tasks required to log in.

For background on what the A / AA / AAA letters actually mean, see Conformance Levels. For the four POUR principles and how the catalog is organized, start at the WCAG 2.2 fundamentals.

2.4.11 Focus Not Obscured (Minimum) — AA

Plain English: when a user tabs to a control, the control must not be entirelyhidden by something the page authored — typically a sticky header, sticky footer, cookie banner, or floating chat button. Browser-supplied UI (the URL bar, on-screen keyboards) is out of scope. See W3C SC 2.4.11.

layout.csshtml
<!-- Bad: a sticky footer can hide the focused element behind it. -->
<style>
  .cookie-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: 88px; /* overlaps the bottom of the viewport */
    background: #111;
    color: #fff;
  }
</style>

<!-- Good: reserve space so a focused element scrolled to the bottom
     is not fully hidden by the sticky region. -->
<style>
  :root {
    --sticky-cookie-bar-height: 88px;
  }

  body {
    /* Anything that programmatically scrolls into view (focus moves,
       anchor jumps, etc.) gets a margin equal to the sticky bar so
       the focused element is never fully obscured. */
    scroll-padding-bottom: var(--sticky-cookie-bar-height);
  }

  :focus-visible {
    scroll-margin-bottom: var(--sticky-cookie-bar-height);
  }
</style>

What automation catches: partial. Static analysis can flag a sticky element with high z-index that overlaps the viewport edge, but it cannot reliably prove that every focusable element would or would not be obscured at every scroll position. axe-core and IBM Equal Access do not currently produce a deterministic 2.4.11 violation; treat scanner silence as inconclusive, not as a pass.

Manual test step: open the page, scroll to the bottom, then press Tab repeatedly from the top. Every focused element should be visible. Repeat with the page scrolled all the way down so any sticky footer is in play. Then open a dialog (modal, drawer, off-canvas menu) and tab inside it: focus must remain inside and stay visible. The three most common ways real sites fail this are a cookie banner that loads late and covers the bottom of the viewport, a chat-launcher button that floats above an interactive control in the corner, and a sticky-table header that overlaps the first row when the user tabs back to the top. Each gets caught by the test above and fixed with the same scroll-padding and scroll-margin pattern shown in the snippet.

2.5.7 Dragging Movements — AA

Plain English:any feature that uses a drag movement to operate (re-ordering a list, moving a slider thumb, dragging a map) must offer a single-pointer alternative — a click, tap, or keystroke that achieves the same outcome. The point is to support users with tremors, limited dexterity, or assistive devices that do not produce dragging events. See W3C SC 2.5.7.

PriceSlider.tsxtsx
// Bad: drag-only price slider. A user with a tremor, a one-handed
// user, or a switch user cannot operate this control.
function PriceSliderBad({ value, onChange }: {
  value: number;
  onChange: (n: number) => void;
}) {
  return (
    <div
      role="slider"
      aria-valuenow={value}
      aria-valuemin={0}
      aria-valuemax={1000}
      onPointerMove={(e) => {
        // ...compute new value from drag delta...
        onChange(e.clientX);
      }}
    />
  );
}

// Good: native range input. Drag, click-to-position, AND keyboard
// (arrow keys, Home/End, Page Up/Down) all work out of the box.
function PriceSliderGood({ value, onChange }: {
  value: number;
  onChange: (n: number) => void;
}) {
  return (
    <label className="block">
      <span>Maximum price</span>
      <input
        type="range"
        min={0}
        max={1000}
        step={10}
        value={value}
        onChange={(e) => onChange(Number(e.target.value))}
      />
      <output>{value} EUR</output>
    </label>
  );
}

What automation catches:essentially nothing. There is no reliable static signal that a custom “slider” or kanban control is drag-only. A scanner that sees a div[role="slider"] cannot tell whether keyboard arrow keys also work or whether there is an equivalent click target. This is a manual-review SC.

Manual test step:identify every drag-driven feature on the page (reorder, slider, map pan, signature pad, color picker). For each one, unplug your mouse and try to complete the same task with keyboard or with single clicks / taps only. If you can't, the feature fails 2.5.7. The common offenders we find on customer scans are custom kanban boards with no “move to” menu, image cropper widgets that only accept drag, and signature pads on checkout that have no “type your name” alternative. The W3C wants you to provide the equivalent action, not a different action — a kanban move-to-column button is a valid alternative to drag; a contact-form link is not.

2.5.8 Target Size (Minimum) — AA

Plain English:interactive targets must be at least 24×24 CSS pixels, unless one of four exceptions applies — equivalent adjacent targets with enough spacing, inline targets within a sentence, user-agent-rendered controls, or targets whose size is essential to the function (a map pin pixel, for example). See W3C SC 2.5.8. Note this is the AA “minimum” bar at 24px; the AAA version (2.5.5) raises the floor to 44px.

buttons.csscss
/* WCAG 2.2 SC 2.5.8 Target Size (Minimum) — AA
   Interactive controls must be at least 24 x 24 CSS pixels.
   Below uses plain CSS plus a Tailwind alternative side-by-side. */

/* Plain CSS */
.btn-icon {
  min-block-size: 24px;     /* logical equivalent of min-height */
  min-inline-size: 24px;    /* logical equivalent of min-width  */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px;             /* hit-area padding, not just the glyph */
}

/* Tailwind v4 equivalent — uses arbitrary values OR the 6 / 8 utility:
   class="inline-flex items-center justify-center min-h-[24px] min-w-[24px] p-1"
   or, since 24px === 1.5rem === size-6:
   class="inline-flex items-center justify-center size-6 p-1" */

/* Exception: inline targets in a sentence (e.g. a word that is a link)
   are exempt. Targets that are equivalent and adjacent (e.g. a row of
   pagination buttons) only need spacing equivalent to 24x24 between
   their CENTERS, not within each target. */
.pagination a {
  min-block-size: 24px;
  min-inline-size: 24px;
  margin-inline: 4px; /* center-to-center spacing handles the row */
}

What automation catches: most of it. axe-core has a target-size rule (best practice / experimental in some versions, promoted in WCAG 2.2 rule packs) that measures the rendered bounding box of each interactive element. False positives happen when an element gets its hit area from an ancestor (e.g. an icon inside a 44px row); you may need to override the rule on a case-by-case basis. The same reasoning applies to contrast checks — trust the measurement, then verify the context.

Manual test step: set browser zoom to 100%, devtools to mobile emulation (375px viewport), and screenshot every cluster of interactive controls (pagination, social icons, table row actions). Anything that looks pinchable under 24px or that you would mis-tap on a phone is the candidate list to fix.

3.2.6 Consistent Help — Level A

Plain English: if you provide a help mechanism (contact link, phone number, chat button, FAQ link, self-service form) on multiple pages, those mechanisms must appear in the same relative orderon every page that has them. Cognitively, the user learns the layout once. You are not required to put help on every page — only to be consistent when you do. See W3C SC 3.2.6.

SiteFooter.tsxtsx
// Centralize help links in one shared component so the order can
// never drift between marketing, app, and account pages.
export function SiteFooterHelp() {
  return (
    <nav aria-label="Help">
      <ul>
        <li><a href="/help">Help center</a></li>
        <li><a href="mailto:support@example.com">Email support</a></li>
        <li><a href="tel:+3220000000">+32 2 000 00 00</a></li>
        <li>
          <button type="button" onClick={openChat}>
            Live chat
          </button>
        </li>
      </ul>
    </nav>
  );
}

What automation catches: nothing useful. A scanner sees one page at a time. The whole point of 3.2.6 is cross-page consistency. The fix is structural: share a single component for the help block.

Manual test step:open three pages that contain a help mechanism (home, a product page, the checkout). Confirm the help affordances appear in the same order relative to each other on all three. Variation in surrounding content is fine; variation in the order of “chat, email, phone” vs “phone, email, chat” is not.

3.3.7 Redundant Entry — Level A

Plain English: within the same process (signup, checkout, account update), do not ask the user to re-enter information they have already provided. Either auto-populate it, or let them select the previous value. Allowed exceptions are explicitly limited: re-entry is essential (re-typing the password to confirm), security-sensitive (re-typing a one-time code), or the previous information is no longer valid (a credit card has expired). See W3C SC 3.3.7.

CheckoutShippingForm.tsxtsx
// SC 3.3.7 — do not ask the user for the same information twice
// in the same process. Either auto-fill it, or let them pick a
// previously-entered value.

type Address = {
  street: string;
  city: string;
  postalCode: string;
  country: string;
};

export function CheckoutShippingForm({
  billingAddress,
}: {
  billingAddress: Address;
}) {
  const [sameAsBilling, setSameAsBilling] = useState(true);
  const [shipping, setShipping] = useState<Address>(billingAddress);

  return (
    <fieldset>
      <legend>Shipping address</legend>

      {/* Default ON: re-using prior entry is the conformant path. */}
      <label>
        <input
          type="checkbox"
          checked={sameAsBilling}
          onChange={(e) => {
            const checked = e.target.checked;
            setSameAsBilling(checked);
            if (checked) setShipping(billingAddress);
          }}
        />
        Use my billing address for shipping
      </label>

      {!sameAsBilling && (
        <AddressFields
          value={shipping}
          onChange={setShipping}
          /* Standard autocomplete tokens let the browser / password
             manager / form filler reuse data the user has already
             provided in this session or elsewhere. */
          autoCompletePrefix="shipping"
        />
      )}
    </fieldset>
  );
}

What automation catches: partial. Some scanners surface missing or weak autocomplete tokens, which is a related signal: if your address fields lack autocomplete="street-address" / postal-code / country, browsers and password managers cannot reuse data the user already has. But process-level redundancy (asking for billing AND shipping with identical fields and no “same as” option) is not a rule the scanner can express.

Manual test step: walk through your longest multi-step flow (typically checkout or onboarding) and list every field the user has to fill. If the same piece of information (email, name, address, phone) appears more than once and there is no auto-populate or pick-from-prior option, that is your failing spot for 3.3.7.

3.3.8 Accessible Authentication (Minimum) — AA

Plain English: users must be able to authenticate without solving a cognitive function test. That means: passwords must be paste-able (no onpaste="return false"), password managers must work (correct autocomplete attributes), and you may not require the user to transcribe a puzzle, do arithmetic, or remember a long string. Acceptable alternatives include WebAuthn / passkeys, magic links, OAuth, and OTPs that can be auto-filled from SMS or an authenticator app. See W3C SC 3.3.8.

login.htmlhtml
<!-- SC 3.3.8 Accessible Authentication (Minimum) — AA
     Do not require the user to solve a cognitive function test
     (transcribe a CAPTCHA, do mental arithmetic, recall a password
     they cannot paste, etc.) unless an alternative is offered. -->

<form action="/login" method="post">
  <label for="email">Email</label>
  <input
    id="email"
    name="email"
    type="email"
    autocomplete="username"
    required
  />

  <label for="password">Password</label>
  <!-- autocomplete="current-password" lets password managers fill
       the field. Do NOT disable paste; that violates SC 3.3.8 by
       forcing manual transcription. -->
  <input
    id="password"
    name="password"
    type="password"
    autocomplete="current-password"
    required
  />

  <button type="submit">Sign in</button>
</form>

<!-- Bot-protection alternative: server-side risk scoring + an
     accessible second factor (email magic link, WebAuthn, SMS).
     A visual / audio CAPTCHA alone would fail SC 3.3.8 because
     it is itself a cognitive function test. -->

What automation catches: partial. A scanner can flag missing or wrong autocomplete tokens on login forms, detectonpaste handlers that block paste, and detect inline event handlers that disable autofill. It cannot tell whether the rest of your bot-protection pipeline (a CAPTCHA shown only on suspicious sessions, for example) is in the path of every user or only some.

Manual test step:sign in from a fresh browser session using a password manager. Confirm that (1) the password manager autofills, (2) you can paste both email and password from clipboard, and (3) no CAPTCHA appears on a typical “low risk” sign-in. Then sign in over Tor or a fresh IP to see if your risk system blocks legitimate users behind a cognitive-function test.

AAA additions (brief)

AAA criteria are optional for most compliance targets. The W3C itself recommends against requiring full AAA conformance across an entire site. Mentioning them here for completeness.

2.4.12 Focus Not Obscured (Enhanced)

The stricter sibling of 2.4.11. The focused element must not be obscured at all — not even partially — by author-created content. In practice this means avoiding sticky elements that overlap the viewport, or designing them so they never overlap a possible focus position. See W3C SC 2.4.12.

2.4.13 Focus Appearance

Defines a minimum size and contrast ratio for the visible focus indicator: an area at least the size of a 2 CSS-pixel-thick perimeter around the focused control, with a 3:1 contrast ratio between focused and unfocused states. If you have ever wondered whether your custom focus ring is “enough,” this is the criterion that defines “enough.” See W3C SC 2.4.13.

3.3.9 Accessible Authentication (Enhanced)

The stricter sibling of 3.3.8. Even object-recognition tasks (“click on all the traffic lights”) and personal-content tests (“which of these is your security image?”) are disallowed. The practical bar is to support WebAuthn, passkeys, or another no-cognitive-test method as the primary path. See W3C SC 3.3.9.

What was removed: 4.1.1 Parsing

WCAG 2.2 explicitly removes SC 4.1.1 Parsing— the old rule that HTML must parse without certain errors (no duplicate IDs in the same context, no incomplete start/end tags, and so on). The W3C reasoning, captured in the WCAG 2.2 working group decision, is that modern browsers and assistive technologies recover from these parsing errors well enough that the criterion no longer correlates with real accessibility barriers. Pages now meet 4.1.1 by default; you cannot fail it.

Automated checks vs manual review for WCAG 2.2

Per Deque's Automated Accessibility Coverage Report, Deque reported automated tests identified 57.38% of issue instances by volume in its dataset — based on 2,000+ audits across 13,000+ pages and ~300K issues. The new WCAG 2.2 criteria split into three buckets:

  • Mostly automatable: 2.5.8 Target Size (Minimum). Bounding-box measurement is deterministic. Edge cases (parent-provided hit areas, inline text targets) need manual confirmation, but the false-negative rate is low.
  • Partially automatable: 2.4.11 Focus Not Obscured, 2.4.13 Focus Appearance, 3.3.7 Redundant Entry, 3.3.8 Accessible Authentication. Scanners can surface adjacent signals (z-index overlaps, autocomplete tokens, paste-blocking handlers, contrast of focus rings) but cannot prove the SC.
  • Manual only: 2.5.7 Dragging Movements, 3.2.6 Consistent Help. These require multi-page or interaction-time reasoning a static scanner cannot perform.

This is the same shape as the broader 57.38% finding: automation flags a meaningful share of issue volume but cannot, on its own, determine WCAG conformance for any given page; a human-in-the-loop process is needed regardless of the number. We document our take in What Scanners Miss and our recommended workflow in the accessibility testing guide.

How to use this checklist

A defensible WCAG 2.2 conformance workflow has four phases. Do them in order; the documentation phase is the one most teams skip and the one most often asked for during regulator correspondence or an ADA demand-letter response.

  1. Scan. Run an automated scan against every template (home, listing, detail, form, checkout, account). Save the report, dated.
  2. Triage. Group findings by SC. Tackle Level A and the AA additions above first; everything else inherits from your WCAG 2.1 backlog.
  3. Fix. Land code changes in the same component or template. Re-test by re-scanning the page and running the manual step above for each AA addition. The manual step is the load-bearing one.
  4. Document. Update your accessibility statement with the date of the last review, the standard targeted (WCAG 2.2 Level AA), the scan tool, and any known remaining issues. If you are in the EU, this also satisfies your obligation under the EAA to publish current accessibility information.

Frequently asked questions

Do I need to comply with WCAG 2.2 or stick with 2.1?
Stick with whatever standard your legal obligation references. ADA Title II currently mandates WCAG 2.1 Level AA, the EAA references EN 301 549 which currently aligns to 2.1 Level AA, and Section 508 references 2.0 Level AA. WCAG 2.2 is the W3C Recommendation and is what updated regulations will adopt, so new builds should target 2.2 AA to avoid having to come back later. There is no legal penalty for being ahead of the regulation.
Is WCAG 2.2 AA required for EAA?
Not directly today. The EAA references EN 301 549, which is the European harmonized standard. The current version of EN 301 549 (v3.2.1) maps to WCAG 2.1 Level AA. An updated EN 301 549 that references WCAG 2.2 is in progress, and conforming to 2.2 today gives you 2.1 conformance for free since 2.2 only added criteria (and removed 4.1.1 Parsing).
What if I am already 2.1 AA conformant?
You are most of the way to 2.2 AA. The remaining work is the four AA additions: 2.4.11 Focus Not Obscured (Minimum), 2.5.7 Dragging Movements, 2.5.8 Target Size (Minimum), and 3.3.8 Accessible Authentication (Minimum). Plus the two Level A additions if you are not already covering them. A focused engineering sprint can close the gap on a typical SMB marketing site in days to a couple of weeks.
Will my existing automated scanner catch the new SC?
Partially. axe-core, IBM Equal Access, Lighthouse, and similar tools have rolled out rules for 2.5.8 Target Size and partial signals for 2.4.11 and 3.3.8 over the course of 2024 and 2025. None of them can deterministically verify 2.5.7 Dragging Movements or 3.2.6 Consistent Help — those still need manual review. Plan for the human-in-the-loop step instead of assuming scanner silence equals a pass.
How does WCAG 2.2 affect the ADA?
The 2024 ADA Title II rule explicitly references WCAG 2.1 Level AA, not 2.2 — that is the standard state and local government websites must meet by their compliance deadlines. After the DOJ's April 2026 Interim Final Rule extended those dates, the relevant compliance deadlines are April 26, 2027 (entities serving populations of 50,000 or more) and April 26, 2028 (smaller entities and special district governments). For Title III (private businesses), courts continue to reference WCAG generally as the standard. Building to 2.2 AA today is the safe forward-looking choice; conforming to 2.2 inherits 2.1 conformance.
Will WCAG 3.0 invalidate WCAG 2.2?
No. WCAG 3.0 is a working draft, not a Recommendation. Even when it is published, the W3C plan is for 2.x and 3.0 to coexist for years so that organizations and regulations have time to migrate. WCAG 2.2 is the current authoritative reference for the foreseeable future. Build for it, not for a moving target.

How SweepHound supports WCAG 2.2 testing

SweepHound runs a dual-engine scan (axe-core plus IBM Equal Access) against every page you submit. Both engines have updated their rule packs for the WCAG 2.2 additions where automation is even partially possible — notably the target-size rule and the autocomplete / paste-handler signals that flag likely 3.3.8 authentication issues. For every finding the scanner can deterministically flag, we generate a code-level fix snippet with the surrounding DOM context so you can diff it against your source.

What we are honest about: scanners cannot prove a site meets 2.5.7 Dragging Movements or 3.2.6 Consistent Help. SweepHound surfaces these as “needs manual review” line items in your scan report with the specific elements (drag handles, help links) it found so you can run the manual test step yourself. That is what the 57.38% number from Deque means in practice: the scanner is your first pass, not your last word.

See your own results with a free scan: create an account and point us at your homepage. The free tier scans one site so you can decide whether the dual-engine output is useful before you look at pricing. If it is, the paid tiers add scheduled re-scans, multi-site coverage, and authenticated-area scanning for the parts of your app behind a login. Either way, the test plan above is yours to keep — copy it into your runbook, refer to it on your next release, and sign up when you want a dual-engine automated baseline to start from.

Sources

  1. W3C — Web Content Accessibility Guidelines (WCAG) 2.2The normative W3C Recommendation. Cite directly for any SC.
  2. W3C WAI — What’s New in WCAG 2.2Authoritative summary of the 9 new SC and persona examples.
  3. Deque University — WCAG 2.2 resourcesPractitioner reference with techniques and failures per SC.
  4. Vispero — New Success Criteria in WCAG 2.2Practitioner walkthrough of the WCAG 2.2 additions.
  5. Level Access — WCAG 2.2 AA summary and checklistPractitioner checklist; verify against the W3C spec before quoting.
  6. Deque — Automated Accessibility Coverage ReportDeque dataset methodology for the 57.38% issue-instance volume figure.