Accessibility cheat sheet

A scannable Accessibility reference: 18 short snippets across 10 topics, each linking back to the lesson it came from.

At a glance

TopicWhat it covers
Semantic HTML and keyboard accessA native element arrives with behaviour, keyboard support, focus handling and a role that assistive technologylesson
Focus management, ARIA and testingWhen content appears or disappears without a page load, keyboard users can lose their place entirely. Focus rules forlesson
How people use assistive technologyA screen reader reads the accessibility tree, not the pixels. It has two modes: a browse mode that moves element bylesson
Accessible components: modals, menus, tabs and comboboxesDialog focus trapping and returning focus, disclosure and menu patterns, tab and accordion semantics, combobox keyboardlesson
Live regions and dynamic content announcementsThe rule that ties all of this together: after any change, the user must be able to tell what happened and where theylesson
Data tables, charts and data visualisationA scrollable table container must be focusable, or a keyboard user cannot scroll it. A wrapper with tabindex="0" and anlesson
Motion, zoom, reflow and vestibular safetyReduced motion, pausing and stopping animation, 400 percent zoom and reflow, text spacing, orientation, and target sizelesson
Cognitive accessibility: plain language and error recoveryRedundant entry and memory load are the criteria people most often skip, and they are among the cheapest to fix. Everylesson
Accessibility in design systems and SPA frameworksA design system is where accessibility can be solved once. If the button component renders a real button and requireslesson
Auditing, remediation and compliance reportingChoosing automated scanners, structuring a manual audit, prioritising fixes by user impact, VPAT and EN 301 549lesson

Quick snippets

Semantic HTML and keyboard access

Keyboard access and tab order

<!-- avoid: positive tabindex reorders the whole page -->
<input tabindex="1">

<!-- include something that is not focusable by default -->
<div tabindex="0" role="region" aria-label="Terminal output">...</div>

<!-- keep it in the tree, but not in the tab order -->
<button tabindex="-1">Close</button>

<!-- focus target for skip links needs tabindex="-1" to accept focus -->
<h2 id="section-2" tabindex="-1">Section 2</h2>

Keyboard access and tab order

/* a focus ring that survives on both light and dark backgrounds */
:focus-visible {
  outline: 3px solid #1a5fff;
  outline-offset: 2px;
  border-radius: 2px;
}

/* never remove the indicator without a replacement */
/* button:focus { outline: none; }  <- do not do this */

Full lesson: Semantic HTML and keyboard access →

Focus management, ARIA and testing

ARIA, when it is actually needed

<!-- good: native toggle with correct open state -->
<button type="button" aria-expanded="false" aria-controls="menu">Menu</button>
<ul id="menu" hidden>
  <li><a href="/orders">Orders</a></li>
</ul>

<!-- icon-only control needs an accessible name -->
<button type="button" aria-label="Close dialog">
  <svg aria-hidden="true" focusable="false" viewBox="0 0 16 16">...</svg>
</button>

A testing routine that finds real problems

# automated pass in CI, fails the build on new violations
npx axe https://localhost:3000 --exit

# or in a Playwright test
npx playwright test a11y.spec.js

Full lesson: Focus management, ARIA and testing →

How people use assistive technology

Screen readers are not one behaviour

<!-- what a screen reader announces depends entirely on this markup -->
<nav aria-label="Breadcrumb">
  <ol>
    <li><a href="/guides">Guides</a></li>
    <li><a href="/guides/dns" aria-current="page">DNS</a></li>
  </ol>
</nav>

<!-- without a label, this is announced as an unnamed navigation region -->
<nav>...</nav>

Magnification, voice, switches and captions

<!-- voice control matches the visible text - keep them identical -->
<button type="submit">Save changes</button>

<!-- this button cannot be activated by voice, because the label is a picture -->
<button type="submit" aria-label="Save changes"><svg aria-hidden="true">...</svg></button>

<!-- captions need a real track, not an auto-generated guess -->
<video controls>
  <source src="/talk.mp4" type="video/mp4" />
  <track kind="captions" src="/talk.en.vtt" srclang="en" label="English" default />
  <track kind="descriptions" src="/talk.descriptions.en.vtt" srclang="en" label="Audio description" />
</video>

Testing with real users

When there is no budget for a study

  install a screen reader and complete your primary task with the screen off
  complete the same task using only the keyboard
  zoom the browser to 200 percent and then 400 percent
  turn on the operating system's reduced motion setting
  use voice control for one form on your phone

Five sessions of an hour each find more than any scanner.

Full lesson: How people use assistive technology →

Accessible components: modals, menus, tabs and comboboxes

Modals and dialogs

<dialog id="confirm" aria-labelledby="confirm-title" aria-describedby="confirm-body">
  <h2 id="confirm-title">Delete this project?</h2>
  <p id="confirm-body">This removes the project and everything in it. This cannot be undone.</p>
  <button type="button" data-action="cancel">Cancel</button>
  <button type="button" data-action="delete">Delete project</button>
</dialog>

Comboboxes and libraries

<label for="country">Country</label>
<input id="country" role="combobox" aria-expanded="false" aria-controls="country-list"
       aria-autocomplete="list" autocomplete="country-name" />
<ul id="country-list" role="listbox" aria-label="Countries" hidden>
  <li role="option" id="opt-nl" aria-selected="false">Netherlands</li>
  <li role="option" id="opt-no" aria-selected="false">Norway</li>
</ul>
<!-- and the live region that announces how many results match -->
<p role="status" class="sr-only">2 results available</p>

Full lesson: Accessible components: modals, menus, tabs and comboboxes →

Live regions and dynamic content announcements

Live regions that work

<!-- polite: announced when the user is idle. Use for most updates. -->
<p role="status" aria-live="polite">2 results available</p>

<!-- assertive: interrupts immediately. Use only for errors that need action. -->
<div role="alert">Payment failed. Check your card details.</div>

<!-- a region must be in the DOM before the content is added -->
<div id="cart-status" role="status" aria-live="polite" aria-atomic="true"></div>

<!-- and a busy indicator that is announced once -->
<button type="button" aria-busy="true">Saving...</button>

Async results and validation

// forcing a repeat announcement of the same string
function announce(el, message) {
  el.textContent = "";                  // must reach the DOM before the new text
  requestAnimationFrame(() => { el.textContent = message; });
}

Full lesson: Live regions and dynamic content announcements →

Data tables, charts and data visualisation

Table structure

<!-- a sortable column header, with the state exposed -->
<th scope="col" aria-sort="ascending">
  <button type="button">
    Revenue
    <span aria-hidden="true">&#9650;</span>
  </button>
</th>

<!-- and a table that is scrollable on small screens needs a keyboard-reachable wrapper -->
<div role="region" aria-labelledby="rev-caption" tabindex="0">
  <table aria-labelledby="rev-caption">...</table>
</div>

Dashboards and refreshing data

<section aria-labelledby="panel-orders">
  <h2 id="panel-orders">Orders today</h2>
  <p class="value">1,284 <span class="delta">up 12 percent on yesterday</span></p>
  <p role="status" aria-live="polite" class="sr-only" id="orders-live"></p>
</section>

Full lesson: Data tables, charts and data visualisation →

Motion, zoom, reflow and vestibular safety

Motion and vestibular safety

// read the preference in script when behaviour depends on it
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

function scrollToSection(el) {
  el.scrollIntoView({
    behavior: prefersReducedMotion ? "auto" : "smooth",
    block: "start"
  });
}

Full lesson: Motion, zoom, reflow and vestibular safety →

Cognitive accessibility: plain language and error recovery

Forgiving error recovery

<!-- a confirmation that names the thing, and an undo afterwards -->
<dialog id="delete-project" aria-labelledby="del-title">
  <h2 id="del-title">Delete "Renewal pipeline"?</h2>
  <p>The project and its 42 tasks will be removed. You can restore it for 30 days.</p>
  <button type="button">Cancel</button>
  <button type="button">Delete project</button>
</dialog>

<div role="status" class="toast">
  Project deleted.
  <button type="button">Undo</button>
</div>

Full lesson: Cognitive accessibility: plain language and error recovery →

Accessibility in design systems and SPA frameworks

Preventing regressions

# a CI job that fails a pull request on an accessibility regression
- name: Component accessibility tests
  run: npm run test -- --coverage=false a11y

- name: Scan built pages
  run: npx axe ./dist --exit
  continue-on-error: false

Full lesson: Accessibility in design systems and SPA frameworks →

Auditing, remediation and compliance reporting

Structuring an audit

# a scanner in CI, scoped to the pages that matter
npx pa11y-ci --config .pa11yci.json

# a single page, with a full report
npx pa11y https://example.com/checkout --reporter json > checkout-a11y.json

# and one run in the browser against the rendered DOM
# axe DevTools or the axe-core CLI, which sees client-rendered markup

Conformance reporting and CI

# a pragmatic CI gate: only new violations fail the build
- name: Accessibility scan
  run: npx pa11y-ci --config .pa11yci.json

- name: Fail on new violations
  run: node tools/a11y-diff.js --baseline .a11y-baseline.json --fail-on new

Full lesson: Auditing, remediation and compliance reporting →

FAQ

Is this Accessibility cheat sheet free to use?
Yes. No sign-up and no tracking: the page is static, every example is on the page itself, and you can print it or save it as a one-page reference.
Where do the examples come from?
Every snippet is taken from the 10 lessons of the Accessibility course on this site, and each section links back to the lesson it was pulled from.
How do I go deeper than a cheat sheet?
Open the full Accessibility course — it carries the worked explanations, the edge cases and the exercises behind every line here.

SEO Basics Domains & DNS Web Hosting CDNs & Caching

Last refreshed 2026-09-27.