Auric Artisan · Accessibility
The accessibility checklist
Fifty checks across the whole of WCAG 2.2, each one explained: what it means, who it affects, how to test it, and what the fix looks like in code.
The analyzer decides 11 of these outright and narrows 23 more. The rest needs a person, which is what the explanations are for.
Nothing matches these filters.
Evidence
0 screenshots pinned
No cap on images or on marks, and the pen never touches the picture underneath.
Semantics & structure
What a screen reader builds its map from. Nothing below works if this is wrong.
-
Landmarks wrap every region of the page PARTLY A 1.3.1 header, nav, main, footer — one main per page, and any repeated nav named.
What it means
Landmarks give a screen reader a table of contents for the page: a user can jump straight to the navigation, or to the main content, without listening through everything before it. A page built entirely from div elements offers no such jumps, so every visit starts at the top and walks forward.
Who it affects
Screen reader users navigating by region — the fastest way to move around a page they have not seen before.
How to test it
In the browser console, run the selector below. You want exactly one main, and every nav that appears more than once to carry its own label.
What the fix looks like
document.querySelectorAll('header,nav,main,aside,footer') // exactly one <main>; each repeated <nav> needs aria-labelUsually breaks when
A component library wraps everything in div, or a layout gains a second main during a refactor and nobody notices.
-
Headings describe structure, not size AUTO A 1.3.1 One h1, no skipped levels. Style with CSS; never pick a heading level to get a font size.
What it means
Heading level is an outline, not a type scale. Screen reader users pull up a list of headings to understand and navigate a page, so a jump from h2 to h4 reads as a missing section, and an h3 chosen because it "looked right" puts content in the wrong place in that outline.
Who it affects
Screen reader users, who navigate by heading more than by any other means; also anyone using reader mode or a summarising tool.
How to test it
List every heading in order and read just the text. It should work as a table of contents on its own.
What the fix looks like
[...document.querySelectorAll('h1,h2,h3,h4,h5,h6')] .map(h => h.tagName + ' ' + h.textContent.trim())Usually breaks when
A design hands over "small bold label" and the nearest heading level is used to get the size.
-
html lang is set, and switches on foreign passages AUTO A 3.1.1 It picks the speech synthesiser. A French quote inside English needs its own lang.
What it means
The lang attribute tells assistive technology which pronunciation rules to use. Without it a screen reader reads English with the user default voice, which can render an English page in a Hindi phonology — technically speech, practically noise.
Who it affects
Screen reader users, and anyone using automatic translation or a braille display, where language drives the contraction rules.
How to test it
Check the root element, then search the page for passages in another language and confirm each carries its own lang.
What the fix looks like
<html lang="en"> <p>The dish was <span lang="fr">déjà vu</span>.</p>Usually breaks when
A template ships with lang hard-coded to one language and the site later gains a second.
-
Every route has a unique, front-loaded title PARTLY A 2.4.2 In a SPA the title is yours to set on navigation — the browser will not do it.
What it means
The title is announced on load and is what a user sees in a long list of tabs or in browser history. Put the distinguishing part first: "Invoices — Acme" beats "Acme — Invoices" when the tab is 90 pixels wide.
Who it affects
Everyone with many tabs open; screen reader users, for whom it is the first thing announced on every navigation.
How to test it
Navigate the app client-side and watch document.title change. If it does not, nothing is announcing the new page.
What the fix looks like
// on route change document.title = `${page.name} — Acme`;Usually breaks when
A single-page app changes the view without touching the title, so every route announces the same words.
-
Lists, tables and figures use real elements PARTLY A 1.3.1 A table needs th with scope and a caption. A div grid announces nothing.
What it means
Native elements carry relationships that CSS cannot: a list announces how many items it has, a data table lets a user read a cell together with its row and column headers. Rebuild either from div and that structure is gone, leaving a flat run of text.
Who it affects
Screen reader users reading tabular data, where losing the header association makes the numbers meaningless.
How to test it
Put the cursor in a random data cell with a screen reader running. You should hear the column and row it belongs to.
What the fix looks like
<table> <caption>Revenue by quarter</caption> <tr><th scope="col">Quarter</th><th scope="col">Revenue</th></tr>Usually breaks when
A CSS grid gives the layout the designer wanted, and the semantics are never added back.
-
The reading order matches the visual order BY HAND PRACTICE CSS order, grid placement and absolute positioning all move the eye without moving the DOM.
What it means
Assistive technology and keyboard focus follow the DOM. CSS can reorder what the eye sees without touching it, so a sidebar that reads last but appears first will be reached last — the two orders drift apart silently and only ever surface in testing.
Who it affects
Keyboard and screen reader users, and anyone whose browser fails to load the stylesheet.
How to test it
Disable CSS entirely. The page should still read in a sensible order.
Usually breaks when
A responsive layout uses order or grid-area to rearrange columns at one breakpoint and not another.
Keyboard & focus
The whole product, without a mouse. This is where most single-page apps fail.
-
Every interactive element is reachable and operable by keyboard PARTLY A 2.1.1 A div with onClick is not. Use a button, or add role, tabindex and both key handlers.
What it means
A native button is focusable, announces its role, fires on both Enter and Space, and works with voice control — all of it for free. A div with a click handler has none of that, and reproducing it takes four extra attributes people routinely forget one of.
Who it affects
Keyboard users, switch and voice control users, and screen reader users, who will never even hear that the element exists.
How to test it
Tab through the page and do the primary task without touching the mouse. Anything you can click but cannot reach is a failure.
What the fix looks like
// no <div onClick={save}>Save</div> // yes <button type="button" onClick={save}>Save</button>Usually breaks when
A designer asks for something that "should not look like a button", and the semantics get removed along with the styling.
-
No keyboard trap — focus can always get back out BY HAND A 2.1.2 Modals, embedded players and custom editors are the usual offenders.
What it means
A trap is any place focus can enter and cannot leave with the keyboard alone. It is the most severe failure on this list, because the user is not merely blocked from one feature — they are stuck on the page, with no way forward and no way back.
Who it affects
Keyboard-only users. A mouse user closes the dialog and never sees the bug, which is why it survives review.
How to test it
Tab into every dialog, picker, editor and embedded frame, then try to Tab and Escape your way out. Do it in both directions with Shift+Tab.
What the fix looks like
dialog.addEventListener('keydown', (e) => { if (e.key === 'Escape') close(); // and return focus to the trigger });Usually breaks when
A focus trap is added to a modal for correctness, and the release path is never wired to Escape or to the close button.
-
Focus is always visible, and never removed without a replacement PARTLY AA 2.4.7 outline: none with nothing in its place is the single most common accessibility bug in the wild.
What it means
The focus ring is the keyboard user cursor. Remove it and they are typing blind — they cannot tell which control Enter is about to activate. :focus-visible solves the reason it is usually removed, by showing the ring for keyboard focus and not after a mouse click.
Who it affects
Everyone using a keyboard, including sighted power users who never think of themselves as needing accessibility features.
How to test it
Tab through every control on the page and watch. If you lose track of where you are, so will everyone else.
What the fix looks like
:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; } /* never `outline: none` without a replacement */Usually breaks when
A reset stylesheet strips outlines site-wide on day one and nobody puts anything back.
-
Focus order follows meaning PARTLY A 2.4.3 No positive tabindex. tabindex="-1" for programmatic targets, "0" to add to the order.
What it means
Tab order comes from the DOM. A positive tabindex jumps the element to the front of the whole page order, which breaks the sequence everywhere else — one tabindex="3" quietly reorders every control on the page around it.
Who it affects
Keyboard and screen reader users following a form or a flow in sequence.
How to test it
Tab from the top and note the order. It should match the order you would read the page aloud in.
What the fix looks like
tabindex="0" // put it in the natural order tabindex="-1" // focusable by script only tabindex="3" // almost always a mistakeUsually breaks when
Someone reaches for tabindex to fix one control and reorders the page.
-
Focus is managed across route changes and dialogs BY HAND PRACTICE On open, move focus in; on close, return it to the trigger. On navigation, move it to the new h1.
What it means
A client-side route change replaces the content but leaves focus wherever it was — often on a link that no longer exists, which drops focus to the top of the document with no announcement. The fix is to move focus deliberately and to say what changed.
Who it affects
Screen reader and keyboard users, for whom an unannounced navigation is indistinguishable from nothing happening.
How to test it
Activate a link with the keyboard, then press Tab. If you are back at the browser chrome, focus was lost.
What the fix looks like
// after render headingRef.current.focus(); // h1 with tabindex="-1" // on dialog close triggerRef.current.focus();Usually breaks when
The router animates the transition and focus is forgotten because the page looks like it moved.
-
A skip link comes first and actually moves focus PARTLY A 2.4.1 It must be the first tabbable thing, visible on focus, and target a focusable container.
What it means
Without a skip link, every visit to every page starts by tabbing through the whole navigation. The common failure is subtle: the link scrolls the page but focus stays behind, so the next Tab lands back in the menu the user was escaping.
Who it affects
Keyboard users on any site with more than a handful of navigation links.
How to test it
Load the page, press Tab once, press Enter, then press Tab again. The next stop must be inside the main content.
What the fix looks like
<a class="skip" href="#main">Skip to main content</a> <main id="main" tabindex="-1">Usually breaks when
The target is a div with no tabindex, so the browser scrolls but does not move focus.
-
Pointer targets are at least 24x24 CSS pixels AUTO AA 2.5.8 New in WCAG 2.2. Spacing counts toward it — small icons need room around them, not just size.
What it means
Small targets are hard to hit for anyone with a tremor, on a moving train, or using a stylus. WCAG 2.2 added a 24px floor, and it can be satisfied either by making the target bigger or by giving it enough clear space that a missed tap does not hit its neighbour.
Who it affects
Anyone with reduced fine motor control, and every touch user in imperfect conditions.
How to test it
Measure the hit area, not the icon. A 16px icon in a 44px button passes; two 16px icons 2px apart do not.
What the fix looks like
.icon-btn { min-inline-size: 24px; min-block-size: 24px; } /* or leave 24px of clear space between targets */Usually breaks when
A dense toolbar shrinks on mobile, where the targets need to be larger rather than smaller.
Forms & errors
Where an inaccessible product stops being annoying and starts costing money.
-
Every control has a programmatic label AUTO A 3.3.2 A placeholder is not a label. It vanishes on input and many screen readers skip it.
What it means
The label is what a screen reader announces when focus lands on a field, and what voice control users say to reach it. A placeholder disappears the moment someone types, taking the only description of the field with it — which is worst for the people most likely to need it back.
Who it affects
Screen reader users, voice control users, and anyone who looks away mid-form and returns to a row of empty boxes.
How to test it
Focus each field with a screen reader running. If you hear "edit, blank" and no name, it has no label.
What the fix looks like
<label for="email">Email</label> <input id="email" type="email" autocomplete="email"> <!-- or, visually hidden --> <input aria-label="Search">Usually breaks when
A minimal design removes the labels, and placeholders are pressed into service as a substitute.
-
Errors are identified in text and tied to the field PARTLY A 3.3.1 aria-describedby links the message; aria-invalid marks the state. Colour alone says nothing.
What it means
An error has to say three things: that something is wrong, which field it is wrong on, and what to do about it. A red border says the first, vaguely, to people who can see red — the association and the instruction have to be programmatic and in words.
Who it affects
Screen reader users, colour-blind users, and anyone under enough pressure to miss a subtle colour change.
How to test it
Submit an invalid form with a screen reader on. You should hear the count, then be able to reach each field and hear its message.
What the fix looks like
<input id="email" aria-invalid="true" aria-describedby="email-err"> <p id="email-err">Enter an email address, like [email protected]</p>Usually breaks when
Validation is implemented visually first, and the ARIA wiring is left as a follow-up ticket.
-
Common fields declare autocomplete AUTO AA 1.3.5 name, email, tel, address — it is a requirement, and it halves the typing for everyone.
What it means
The autocomplete attribute names what a field collects using a fixed vocabulary, which lets browsers fill it and lets some assistive technology show a familiar icon in place of a word. It is one of the rare criteria where doing the accessible thing measurably lifts conversion.
Who it affects
People with motor or cognitive disabilities for whom typing an address is a real cost — and everyone else, who just gets a faster form.
How to test it
Check every personal-detail field against the WCAG token list. Watch the browser offer to fill them.
What the fix looks like
<input name="tel" type="tel" autocomplete="tel"> <input name="postcode" autocomplete="postal-code">Usually breaks when
A custom input component drops unrecognised attributes on the way to the DOM.
-
Related controls are grouped with fieldset and legend PARTLY A 1.3.1 Radio sets and checkbox groups are meaningless read one at a time.
What it means
A radio button announces its own label but not the question it answers. The legend supplies that question, so "Standard delivery, radio, 1 of 3" becomes "Delivery method: standard delivery, radio, 1 of 3".
Who it affects
Screen reader users, who otherwise hear the options without ever hearing what is being asked.
How to test it
Focus a radio in a group. If you cannot tell what the group is for, it needs a legend.
What the fix looks like
<fieldset> <legend>Delivery method</legend> <label><input type="radio" name="ship"> Standard</label> </fieldset>Usually breaks when
fieldset is hard to style, so it gets replaced by a div and a heading.
-
Validation is announced, not just painted BY HAND PRACTICE A live region or a focus move — otherwise a screen reader user submits into silence.
What it means
Client-side validation usually re-renders the form in place. Nothing about that re-render is announced, so a screen reader user presses Submit, hears nothing, and concludes the button is broken.
Who it affects
Screen reader users. This is the difference between a form that is hard and a form that is impossible.
How to test it
Submit an invalid form with the screen reader on and your eyes closed. If you learn nothing, neither do they.
What the fix looks like
<div role="alert">2 problems stop this form being submitted</div> // or move focus to the summary, then to the first bad fieldUsually breaks when
The error summary is rendered before it exists in the DOM, so the live region has nothing to announce.
-
Legal and financial submissions are reversible or confirmed BY HAND A 3.3.4 Reversible, checked, or confirmed. Pick one before taking the payment.
What it means
For anything that costs money, forms a contract, or deletes data, WCAG asks for one of three protections: the action can be undone, the input is checked and correctable, or the user gets a confirmation step before it is final.
Who it affects
People with cognitive disabilities and anyone who mis-taps — which, given enough traffic, is everyone.
How to test it
Walk the checkout. Is there a review step, an undo window, or validation that catches the mistake before the charge?
Usually breaks when
A one-click flow is added for speed and the confirmation step is what gets cut.
Images & media
Alt text is a decision, not a field to fill in.
-
Every image is either described or explicitly decorative PARTLY A 1.1.1 alt="" and aria-hidden for decoration. A filename in the alt is worse than nothing.
What it means
Alt text answers one question: what would a sighted person get from this image that they would not get from the surrounding text? If the answer is nothing, alt="" is the correct, deliberate value — an empty alt is a decision, a missing alt attribute is an oversight, and screen readers treat them differently.
Who it affects
Screen reader users; also anyone on a slow connection where images do not load.
How to test it
Turn images off. Anything you now cannot understand needed better alt text; anything now cluttered with filenames needed alt="".
What the fix looks like
<img src="q3.png" alt="Revenue fell 12% in Q3, the first drop since 2019"> <img src="flourish.svg" alt="">Usually breaks when
A CMS makes alt a required field, so authors type the filename to get past it.
-
Text in an image is repeated in real text BY HAND A 1.4.5 It cannot be resized, restyled, translated or searched — screenshots of code are the worst case.
What it means
Text baked into a picture is invisible to search, translation, reader modes and text-spacing overrides, and it blurs when someone zooms. A code screenshot in documentation cannot be copied, read aloud, or searched for the error message it shows.
Who it affects
Low-vision users who zoom or restyle text, and anyone reading in a second language.
How to test it
Try to select the text with the mouse. If you cannot, it is a picture.
Usually breaks when
A designed quote or a code sample is exported as PNG because it was quicker than building it.
-
Video has captions; audio has a transcript BY HAND A 1.2.2 Auto-captions are a draft. Someone reads them before they ship.
What it means
Captions carry dialogue and the sounds that matter; a transcript makes the same content searchable and skimmable. Machine captions get names, jargon and figures wrong at exactly the moments those things matter most, so they are a starting point, not a deliverable.
Who it affects
Deaf and hard-of-hearing users; and the far larger group watching with the sound off in public.
How to test it
Watch with the sound off. Then read the caption track for the words a machine would not know.
Usually breaks when
Auto-captions are enabled once, and nobody reads them again.
-
Video has audio description where it carries visual information BY HAND AA 1.2.5 If the picture says something the soundtrack does not, it needs describing.
What it means
Audio description narrates what is shown but not said — a diagram, an on-screen figure, a demonstration performed in silence. Where a video is planned well, the narration covers this and no separate track is needed.
Who it affects
Blind and low-vision users watching a video whose meaning is partly visual.
How to test it
Listen without watching. Note every moment you lose the thread.
Usually breaks when
A product demo shows the interface while the voiceover says "as you can see here".
-
Nothing plays automatically for more than three seconds PARTLY A 1.4.2 Or there is a control to stop it, reachable before everything else.
What it means
Autoplaying audio competes with a screen reader speaking, and the two cannot be separated by ear. The stop control has to come early in the focus order, because reaching it is exactly what the noise makes difficult.
Who it affects
Screen reader users above all, then everyone in an office or a library.
How to test it
Load the page with a screen reader running. If you cannot hear it, that is the failure.
Usually breaks when
A background video ships muted, and a later change adds a soundtrack.
-
Icons carry an accessible name or are hidden PARTLY PRACTICE An icon-only button needs aria-label; an icon beside a label needs aria-hidden.
What it means
Two failures with one cause. An icon-only button with no name announces as "button" and nothing else. An icon left visible to assistive technology beside a text label gets announced twice, or announced as its filename.
Who it affects
Screen reader users, and voice control users who need a name to say out loud.
How to test it
Read the accessibility tree. Every button should have a name; no name should be doubled.
What the fix looks like
<button aria-label="Delete"><svg aria-hidden="true">…</svg></button> <button><svg aria-hidden="true">…</svg> Delete</button>Usually breaks when
An icon component is used both ways and hard-codes one of them.
Colour & contrast
The part an automated tool can genuinely finish for you.
-
Body text reaches 4.5:1, large text 3:1 AUTO AA 1.4.3 Against the composited background — the colour after every translucent layer, not the token.
What it means
Contrast is measured between the text and what is actually behind it. Translucent overlays, tinted cards and gradients all change that background, so the number in the design token is frequently not the number on screen — a colour can pass on white and fail on the card it lives in.
Who it affects
Low-vision users, everyone over about forty, and anyone outdoors in sunlight.
How to test it
Sample the rendered pixels, not the CSS values. Composite every translucent layer before comparing.
What the fix looks like
/* 4.5:1 body, 3:1 for 24px or 18.5px bold */Usually breaks when
A grey is chosen against white, then reused on a cream surface where it no longer passes.
-
Controls and meaningful graphics reach 3:1 AUTO AA 1.4.11 Input borders, toggles, chart series, focus rings.
What it means
Text is not the only thing that has to be seen. The boundary that tells you where an input begins, the toggle that shows a setting is on, the line in a chart — all need 3:1 against what surrounds them. Hairline borders are the usual casualty of this rule.
Who it affects
Low-vision users, who otherwise cannot find the edges of the controls.
How to test it
Measure the control boundary against the page, and the parts of a graphic that carry meaning against their surroundings.
Usually breaks when
A very light border is chosen for elegance, at about 1.2:1.
-
Colour is never the only carrier of meaning PARTLY A 1.4.1 Links underlined, errors iconned, chart series labelled or patterned.
What it means
If removing all colour removes the information, colour was doing the work alone. The fix is a second cue that survives greyscale: an underline, an icon, a shape, a direct label, a pattern.
Who it affects
About one in twelve men and one in two hundred women, plus anyone printing in mono.
How to test it
Screenshot it and desaturate. Anything you can no longer tell apart is a failure.
Usually breaks when
A status system is built on red, amber and green, and the shapes are added only for the icons.
-
Hover, focus, active and selected states all pass too PARTLY AA 1.4.11 A rule that wins at rest can lose on hover — measure the state, not the resting colour.
What it means
Contrast is usually checked once, in the resting state. Every other state is a different pair of colours, and a hover that swaps a background without swapping the text is the classic way a passing button becomes unreadable at the moment it is being used.
Who it affects
Low-vision and keyboard users — the focus state is the one a keyboard user sees most.
How to test it
Measure each state separately: rest, hover, focus, active, selected, disabled.
Usually breaks when
A hover fills the button with the brand colour and the label stays white.
-
Dark mode and forced-colors are checked separately PARTLY PRACTICE An inverted palette almost never passes, and Windows High Contrast drops your backgrounds entirely.
What it means
Dark mode is a second palette, not a filter, and needs its own measurements. Forced-colors mode goes further: the operating system replaces your colours wholesale, so anything carried by a background image, a shadow or a gradient simply disappears.
Who it affects
Low-vision users, who are the main users of forced-colors mode.
How to test it
Run the full contrast pass again in dark mode. Then turn on Windows High Contrast and look for what vanished.
What the fix looks like
@media (forced-colors: active) { .card { border: 1px solid CanvasText; } }Usually breaks when
A focus ring is drawn with box-shadow, which forced-colors mode removes.
-
Simulated for protanopia, deuteranopia and tritanopia AUTO PRACTICE On real screens, not only on the swatch sheet.
What it means
Simulation shows what a palette becomes for the three common types of colour-vision deficiency. Palettes that look distinct on a swatch sheet often collapse into two colours once they are small, adjacent and rendered as chart series.
Who it affects
Roughly one in twelve men.
How to test it
Simulate each type on real screens — the chart, the status chips, the map — not on the colour ramp in isolation.
Usually breaks when
The palette is tested and the interface built from it is not.
Motion & preferences
The settings the operating system already knows about.
-
prefers-reduced-motion is honoured PARTLY AAA 2.3.3 Not only decorative animation — parallax, autoplaying carousels and scroll-jacking.
What it means
Vestibular disorders make large motion genuinely sickening: parallax, zooming transitions and scroll-jacking can cause nausea and migraine that outlast the visit. The operating system already knows the preference; honouring it costs one media query.
Who it affects
People with vestibular disorders and migraine — and anyone who finds heavy motion tiring.
How to test it
Turn on Reduce Motion in the OS and reload. Large movement should be gone, not merely faster.
What the fix looks like
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; } }Usually breaks when
The query covers CSS transitions, and a JavaScript scroll animation is left running.
-
Nothing flashes more than three times a second BY HAND A 2.3.1 This one can cause seizures. It is not a preference.
What it means
Flashing between about 3 and 55 times a second can trigger a seizure in people with photosensitive epilepsy. This is the one item on the list where the consequence of getting it wrong is a medical emergency rather than an inconvenience.
Who it affects
People with photosensitive epilepsy.
How to test it
Look for rapid flashing or fast red transitions in video, animation and loading states.
Usually breaks when
A glitch effect or a strobing loader is added for style.
-
Moving or auto-updating content can be paused PARTLY A 2.2.2 Carousels, tickers, live feeds — pause, stop or hide.
What it means
Anything that moves, blinks or updates by itself for more than five seconds needs a way to stop it. Motion beside text pulls attention away mid-sentence, and content that rewrites itself while being read is impossible to follow.
Who it affects
People with attention-related and cognitive disabilities; screen reader users, when the content changes as it is read.
How to test it
Find every moving thing on the page and look for its pause control.
Usually breaks when
A hero carousel advances on a timer with no controls at all.
-
Timeouts are announced, or there are none BY HAND AAA 2.2.6 A session that dies silently loses the form someone spent twenty minutes on.
What it means
Where inactivity can destroy data, the user has to be warned how long they have — before they start, not after it has gone. People who take longer to read or type are exactly the people timeouts hit.
Who it affects
People with cognitive or motor disabilities, who may need several times the assumed duration.
How to test it
Leave a long form idle past the timeout. Was there a warning, and did the data survive?
Usually breaks when
A session length is set for security and the front end never learns about it.
ARIA & custom widgets
No ARIA beats bad ARIA. Reach for a native element first, every time.
-
Custom widgets expose name, role and value PARTLY A 4.1.2 And keep them in sync as state changes. A silent aria-expanded is a broken disclosure.
What it means
Every control has to tell assistive technology three things: what it is called, what kind of thing it is, and what state it is in. The hard part is the third — the state has to be updated every time it changes, and a stale aria-expanded is worse than none, because it actively lies.
Who it affects
Screen reader and voice control users operating anything that is not a plain link or button.
How to test it
Open the accessibility tree in devtools, operate the widget, and watch the state change with it.
What the fix looks like
<button aria-expanded="false" aria-controls="menu">Filters</button> // on toggle: btn.setAttribute('aria-expanded', String(open))Usually breaks when
The attribute is set in the initial render and never touched again.
-
The widget follows its APG keyboard pattern BY HAND PRACTICE Tabs, menus, comboboxes and trees each have an expected key map. Users know it already.
What it means
A tab list responds to arrow keys, Home and End; a menu closes on Escape and returns focus to its trigger. These conventions are documented in the ARIA Authoring Practices Guide, and users of assistive technology have learned them — inventing your own means they have to learn yours.
Who it affects
Screen reader and keyboard users who already know how these components behave everywhere else.
How to test it
Open the APG page for the pattern and work through its key map on your implementation.
Usually breaks when
A component gets the roles right and the keyboard handling never gets written.
-
Status messages reach a live region PARTLY AA 4.1.3 polite for confirmations, assertive only for genuine interruptions. Never both.
What it means
A message that appears without taking focus is invisible to a screen reader unless it lands inside a live region. The container has to exist in the DOM before the text arrives, or there is nothing there to observe the change.
Who it affects
Screen reader users, who otherwise never learn that anything saved, failed or finished.
How to test it
Trigger every toast, saved-state and result count with a screen reader running.
What the fix looks like
<!-- render the container empty, then fill it --> <div role="status" aria-live="polite">Saved</div>Usually breaks when
The whole toast including its live region is inserted at once, so nothing is announced.
-
No aria-hidden on a focusable element AUTO PRACTICE It creates a control a screen reader cannot see but can still land on.
What it means
aria-hidden removes an element from the accessibility tree without removing it from the focus order. Focus can land somewhere that, as far as the screen reader is concerned, does not exist — so the user hears nothing at all and cannot tell what happened.
Who it affects
Screen reader users, for whom this presents as focus vanishing.
How to test it
Search for aria-hidden="true" and check nothing inside it is focusable.
What the fix looks like
// hide from everyone, not just from AT el.hidden = true; // or inert on the containerUsually breaks when
A modal hides the background with aria-hidden and leaves the links behind it tabbable.
-
Link text makes sense out of context PARTLY A 2.4.4 "Read more" repeated eleven times is a list of eleven identical links.
What it means
Screen reader users often pull up a list of every link on the page to navigate. In that list there is no surrounding paragraph, so eleven "read more" links become eleven identical entries with no way to tell them apart.
Who it affects
Screen reader users navigating by link; also anyone scanning rather than reading.
How to test it
Extract every link text on the page and read the list. Any duplicate that leads somewhere different is a failure.
What the fix looks like
<a href="/q3">Read the Q3 report</a> <!-- or keep the visible text and extend it --> <a href="/q3">Read more<span class="visually-hidden"> about Q3</span></a>Usually breaks when
A card component takes a fixed call to action and is reused down a whole index page.
Zoom, reflow & spacing
The same page in the conditions people actually browse it.
-
No horizontal scroll at 320 CSS pixels wide AUTO AA 1.4.10 Equivalent to 400% zoom on a desktop. Two-dimensional scrolling is the failure.
What it means
At 400% zoom a 1280px desktop viewport becomes 320px of usable width. Content must reflow into that single column: having to scroll sideways to read every line of every paragraph is what the criterion exists to prevent.
Who it affects
Low-vision users who browse zoomed in permanently, and every small-phone user.
How to test it
Set the viewport to 320px, or zoom to 400%. Nothing may require sideways scrolling except data tables and code.
Usually breaks when
A fixed-width element — a table, an embed, a long unbroken string — sets a floor the layout cannot go below.
-
Text resizes to 200% without loss PARTLY AA 1.4.4 Fixed-height containers with overflow: hidden are where the text goes.
What it means
Text must double in size without content being cut off or made unusable. The usual failure is a container with a fixed height: the text grows, the box does not, and the last line is clipped or hidden entirely.
Who it affects
Low-vision users, and anyone whose browser has a larger default font size than yours.
How to test it
Zoom text only to 200%. Look for clipped lines, overlaps and buttons whose labels no longer fit.
What the fix looks like
/* let it grow */ .card { min-block-size: 120px; } /* not height: 120px */Usually breaks when
A card grid is given a fixed height so the rows line up.
-
User text-spacing overrides do not break the layout PARTLY AA 1.4.12 Line height 1.5, paragraph spacing 2em, letter 0.12em, word 0.16em — nothing may be clipped.
What it means
Some users apply a stylesheet that opens up spacing to make text readable, particularly people with dyslexia. WCAG names exact values that must survive without losing content — which mostly means not fixing the height of anything that holds text.
Who it affects
Dyslexic and low-vision users who override spacing to read comfortably.
How to test it
Apply the four values as a user stylesheet and look for clipping and overlap.
What the fix looks like
* { line-height: 1.5 !important; letter-spacing: .12em !important; word-spacing: .16em !important; } p { margin-block-end: 2em !important; }Usually breaks when
A component sets an exact height to match a design, and a fifth word arrives.
-
Both orientations work PARTLY AA 1.3.4 No locking to portrait unless the content genuinely requires it.
What it means
Many users have a device fixed in one orientation — mounted on a wheelchair, on a stand, on an arm. Locking the interface to the other one makes it unusable rather than merely awkward.
Who it affects
People whose device is physically mounted, and anyone with a keyboard case.
How to test it
Rotate the device. The layout should adapt rather than refuse.
Usually breaks when
A mobile app-style layout assumes portrait and locks it in the manifest.
-
Focused elements are not hidden behind sticky chrome BY HAND AA 2.4.11 New in 2.2, and a sticky header plus scroll-into-view is exactly how it happens.
What it means
Tabbing forward scrolls the next control into view, and a sticky header can sit exactly where it lands — so the element has focus, is scrolled to, and is completely covered. Keyboard users are left typing into something they cannot see.
Who it affects
Keyboard users on any page with a sticky header or a fixed toolbar.
How to test it
Tab down a long page with sticky chrome and watch for the focused control disappearing underneath it.
What the fix looks like
/* keep the focused element clear of the sticky header */ :target, :focus-visible { scroll-margin-block-start: 6rem; }Usually breaks when
A sticky header is added late, long after the focus order was tested.
Testing & proof
How it stays fixed after the sprint that fixed it.
-
An automated pass runs in CI on every pull request AUTO PRACTICE It catches about a third. That third should never reach a human reviewer again.
What it means
Automated rules reliably find missing alt attributes, unlabelled fields, contrast failures and broken ARIA references. That is roughly a third of what matters, and it is the third that is tedious to find by hand — so it belongs in CI, freeing review for the two thirds that need judgement.
Who it affects
Everyone downstream, including the reviewers who stop re-finding the same class of bug.
How to test it
Open a pull request that introduces an unlabelled input. The build should fail.
What the fix looks like
# fail the build, do not just report npx axe-ci $URL --exit-codeUsually breaks when
The job is added as advisory and stays permanently amber.
-
A keyboard-only pass is part of review BY HAND PRACTICE Unplug the mouse and do the primary task. Ten minutes, most of the remaining bugs.
What it means
The cheapest high-yield test there is. Most focus traps, invisible focus rings, unreachable controls and broken dialogs surface within a few minutes of trying to complete one real task without a pointer.
Who it affects
Keyboard, switch and voice users — and it doubles as a check on your focus management.
How to test it
Put the mouse out of reach and complete the main flow. Note every point you get stuck.
Usually breaks when
It is nobody specific job, so it happens the week before an audit.
-
A screen reader pass on one real combination BY HAND PRACTICE NVDA with Firefox, or VoiceOver with Safari. Not the browser plugin that reads the DOM.
What it means
Screen readers differ from each other and from what the accessibility tree suggests they will do. Testing one real pairing end to end teaches more than reading three specifications, and it is the only way to hear what your live regions actually announce.
Who it affects
Screen reader users. Everything else on this list is inference; this is observation.
How to test it
Pick one pairing and complete the primary task with the screen reader on and the monitor off.
Usually breaks when
The team tests with a browser extension that reports the tree rather than speaking it.
-
Findings carry evidence and a criterion BY HAND PRACTICE A screenshot and a number turn "this feels wrong" into something a developer can close.
What it means
A finding without evidence gets argued about; a finding with a marked-up screenshot and a criterion number gets fixed. It also gives you an audit trail with a date on it, which is what a procurement question actually asks for.
Who it affects
The developer who has to reproduce it, and whoever answers the compliance questionnaire.
How to test it
Read your last three findings. Could someone reproduce each one without asking you a question?
Usually breaks when
Findings are recorded in a spreadsheet with a column for the page and none for the proof.
-
People with disabilities are in the testing loop BY HAND PRACTICE Every checklist including this one is a proxy for that, never a replacement.
What it means
A checklist encodes what previous failures taught someone else. It cannot tell you that a flow is technically conformant and still exhausting, or that a pattern is correct and unfamiliar. Only the people who use this software with assistive technology every day can.
Who it affects
Everyone — this is the check that finds what the other forty-six were a proxy for.
How to test it
Ask when a disabled user last tried the flow you are shipping. If the answer is never, that is the finding.
Usually breaks when
Conformance is treated as the goal rather than as the floor.
Turn the flags into a report
What the report will contain
0
Every one, with its criterion, the explanation and any screenshot.
0
Listed by name, so a reader can see what you did check.
0
Carried as you marked them — “N/A” on its own is not evidence.
50
Named as untouched. A check you did not look at is not a pass.
Decided, by level
Evidence No screenshots attached 0 screenshots across 0 checks
Preview — the first lines, as they will read
Three ways out
Your work stays on this device. The checks, your reasons and every screenshot live in this browser and go nowhere until you press one of the buttons above. Clearing site data clears them too.
Before you send it
50 of the checks are untouched, and the report says so on its first page. That is the honest thing, and it is the first thing a reviewer will ask about — so either work them or say in the summary why they are out of scope.
Every check has been decided. The report says so, and that is a claim worth making carefully — it is still a record of your process, not a conformance statement.
A worked checklist is evidence of a process, not a conformance claim. What a claim actually needs →
What the levels mean, and what the law asks for
The four levels on this page
22
The floor. Nearly every instrument below names it, or something built on it.
13
What the statutes and procurement documents actually cite. A + AA is the legal line.
2
Stricter than any law here requires. Worth doing; never demanded wholesale.
13
No criterion covers it, and every audit finds it anyway.
WCAG 2.1 Level AA is the common denominator almost everywhere. The UK and Australia have already moved to 2.2 AA, and EN 301 549 V4 takes the European standard there too. Build to 2.2 AA and you are above every line on this page.
India
Standard · WCAG 2.1 AA via GIGW 3.0| Rights of Persons with Disabilities ActAct 49 of 2016 — ss. 40, 42, 46 | s. 40 empowers the Union to prescribe accessibility standards; s. 42 requires information and communication technology to be accessible; s. 46 puts the duty on service providers. Non-compliance is an offence under s. 89. | 2016 |
| Rajive Raturi v. Union of IndiaSupreme Court of India | Held that Rule 15's merely recommendatory accessibility guidelines were ultra vires s. 40, and gave the Union three months to frame a mandatory floor. This is why Indian accessibility is tightening now. | 8 Nov 2024 |
| GIGW 3.0Guidelines for Indian Government Websites and Apps — NIC | Covers government websites, portals, web applications and mobile apps, and names WCAG 2.1 Level AA. STQC certifies compliant sites. | 2023 |
| IS 17802 (Parts 1 & 2)Bureau of Indian Standards | Accessibility requirements for ICT products and services. Rule 15 has required them since May 2023. | 2021 |
| Draft RPwD (Amendment) Rules, 2026S.O. 3962(E), 16 July 2026 — draft for comment | Would make IS 17802 binding for websites, apps, software, documents and ICT hardware, backed by a published accessibility conformance report. Not in force yet; check its status before relying on it. | Jul 2026 |
Binds government, establishments and service providers — public and private
United States
Standard · WCAG 2.1 AA — Section 508 still 2.0 AA| ADA Title II — DOJ final rule28 CFR Part 35, published April 2024 | State and local government web content and mobile apps must meet WCAG 2.1 Level AA. In April 2026 the DOJ pushed both deadlines back a year: large entities to April 2027, smaller entities and special districts to April 2028. The underlying duty not to discriminate never paused. | 2027 / 2028 |
| Section 508, Rehabilitation Act1973 as amended — the 2017 Refresh | Federal agencies and everything they buy. Incorporates WCAG 2.0 Level AA by reference — still 2.0, which is why a VPAT or ACR often reads a version behind. | 2018 |
| Section 504HHS rule, 45 CFR 84 Subpart I | Recipients of HHS funding — hospitals, clinics, social service agencies, universities — to WCAG 2.1 Level AA: from May 11, 2027 with 15 or more employees, May 10, 2028 with fewer. | 2027 / 2028 |
| ADA Title IIIpublic accommodations | No technical standard in the statute, and none adopted. This is where almost all private litigation happens, with WCAG cited as the practical measure. | 1990 |
Binds federal, state and local government; private business via Title III litigation
European Union
Standard · EN 301 549 V3.2.1 → WCAG 2.1 AA| European Accessibility ActDirective (EU) 2019/882 | The one that reached the private sector: e-commerce, consumer banking, e-books, electronic communications, transport ticketing, ATMs. Enforceable since 28 June 2025. Service microenterprises are exempt. | 28 Jun 2025 |
| Web Accessibility DirectiveDirective (EU) 2016/2102 | Public sector websites and mobile apps, with a published accessibility statement and a working feedback route as hard requirements. | 2019 / 2021 |
| EN 301 549the harmonised standard — V3.2.1, March 2021 | What both directives are measured against. Clause 9 is WCAG 2.1 Level AA. V4.1.1, adopted in August 2026, moves it to WCAG 2.2 once it is cited in the Official Journal. | V3.2.1 |
Binds public sector and, since 2025, much of the private sector across 27 member states
United Kingdom
Standard · WCAG 2.2 AA| Public Sector Bodies Accessibility RegulationsSI 2018/952 | Public sector to WCAG 2.2 Level AA — raised from 2.1, and monitored against 2.2 since October 2024 — plus a published accessibility statement. | 2.2 since 2024 |
| Equality Act 2010s. 20 — reasonable adjustments | Outcome-based and anticipatory: no standard is named, so WCAG AA is simply the evidence you reach for. Applies to private service providers too. | 2010 |
Binds public sector by regulation, everyone else by duty
Canada
Standard · CAN/ASC-EN 301 549:2024| Accessible Canada ActS.C. 2019, c. 10 + Accessible Canada Regulations | Federally regulated organisations — banks, telecoms, transport — must publish accessibility plans, take feedback and report progress. | 2019 |
| CAN/ASC-EN 301 549:2024Accessibility Standards Canada | Canada adopted the European standard outright: WCAG 2.1 Level AA plus EN's extra ICT requirements. Voluntary when published; regulations made in December 2025 make it binding for federal public bodies from December 2027 and larger federally regulated businesses from December 2028. | 31 May 2024 |
| AODAOntario — Integrated Accessibility Standards, s. 14 | WCAG 2.0 Level AA, excluding live captions and audio description, for large organisations and the public sector since 2021. | 2021 |
Binds federally regulated bodies; provinces add their own
Australia
Standard · WCAG 2.2 AA| Disability Discrimination Act 1992and Maguire v SOCOG, 2000 | An early web accessibility ruling: the Sydney Olympics site was found unlawful. The Act names no standard; the case is why WCAG is the measure. | 1992 |
| Government digital standardswith AS EN 301 549:2024 for ICT procurement | Australia has formally adopted WCAG 2.2 Level AA as the minimum, up from 2.0. | 2.2 AA |
Binds government directly, business through the DDA
Japan
Standard · JIS X 8341-3:2016 → WCAG 2.0| JIS X 8341-3:2016Japanese Industrial Standard | Carries exactly the success criteria of WCAG 2.0, with its own conformance and testing procedure and a published statement of conformity. | 2016 |
| Act on Eliminating Discriminationagainst Persons with Disabilities — 2021 amendment | Reasonable accommodation became legally required of private business, not merely encouraged, from April 2024. | Apr 2024 |
Binds public bodies by standard, private business by duty since 2024
Elsewhere
8 more worth knowingWhat this is not
Orientation, not legal advice. Every row points at a primary source. Dates move — two of the dates here moved in the eighteen months before this review — so check the source before you rely on one.
A worked checklist is not a conformance claim. It is evidence of a process. A claim needs a full evaluation against the whole standard, and the people who use assistive technology every day.
Reviewed 30 September 2026 · 29 instruments · 15 jurisdictions