Accessibility Standards
16 min read

WCAG 2.2: Practical Accessibility Guide

Web Content Accessibility Guidelines (WCAG) 2.2 became a W3C Recommendation in October 2023, adding 9 new success criteria focused on cognitive accessibility, mobile interaction, and focus visibility. This guide covers implementation strategies for semantic HTML, ARIA patterns, and testing methodologies—practical knowledge for building inclusive web experiences that meet legal requirements in the US (ADA) and EU (European Accessibility Act).

Compliance Levels

POUR Principles

Perceivable

Text alternatives, captions,

contrast, adaptable

Operable

Keyboard access, timing,

navigation, focus

Understandable

Readable, predictable,

input assistance

Robust

Compatible with

assistive tech

Level A

Essential

32 criteria

Level AA

Recommended

+24 criteria

Level AAA

Specialized

+30 criteria

WCAG 2.2 structure: POUR principles map to hierarchical compliance levels totaling 86 success criteria

WCAG 2.2 builds on the POUR framework (Perceivable, Operable, Understandable, Robust) with three compliance tiers:

LevelCriteriaPurposeLegal Status
A32Minimum barrier removal—assistive tech cannot function without theseBaseline, rarely sufficient alone
AA+24 (56 total)Balance of impact vs. implementation costRequired by ADA, EU accessibility laws
AAA+30 (86 total)Maximum accessibility; not universally achievableSpecialized contexts only

What’s new in WCAG 2.2 (9 criteria added, 1 removed):

  • Cognitive accessibility: Redundant Entry (A), Accessible Authentication (AA/AAA), Consistent Help (A)—no memory tests, no duplicate data entry
  • Motor accessibility: Target Size Minimum 24×24px (AA), Dragging Movements alternatives (AA)
  • Focus visibility: Focus Not Obscured (AA/AAA), Focus Appearance (AAA)—sticky headers can’t hide focused elements
  • Removed: 4.1.1 Parsing—browsers now handle HTML robustly; assistive tech no longer parses markup directly

Implementation priorities:

  1. Semantic HTML provides 80% of accessibility for free—landmarks, headings, native form controls
  2. ARIA supplements native semantics for custom widgets—roles, states, and live regions
  3. Automated testing catches ~57% of individual issues but only ~35% of WCAG criteria; manual testing is non-negotiable
  4. Focus management in SPAs and modals is the most common source of accessibility regressions

WCAG 2.2, published October 2023 (with minor definition updates in December 2024), contains 86 success criteria across three conformance levels. Each level is cumulative—AA includes all of A, AAA includes all of AA.

Level A (32 criteria) establishes minimum viability. Without these, assistive technologies cannot navigate or operate the interface. Failures at this level are complete barriers—a missing form label makes a field unusable for screen reader users, not merely inconvenient.

Level AA (24 additional, 56 total) balances impact against implementation cost. This is the legal target: ADA Title II requires WCAG 2.1 AA by 2026 for state/local government; the European Accessibility Act (enforced June 2025) mandates AA for businesses serving EU customers. Courts consistently use AA as the de facto standard for private sector litigation.

Level AAA (30 additional, 86 total) represents maximum accessibility but is intentionally not a blanket requirement. Some content fundamentally cannot meet certain AAA criteria—a sign language video cannot have a sign language interpretation, and some pages legitimately require reading comprehension above lower secondary education level.

WCAG 2.1 → 2.2 Migration: If you’re already AA-compliant with WCAG 2.1, you need to address 6 new criteria: Focus Not Obscured (2.4.11), Dragging Movements (2.5.7), Target Size Minimum (2.5.8), Consistent Help (3.2.6), Redundant Entry (3.3.7), and Accessible Authentication (3.3.8).

WCAG 2.2 added 9 success criteria and removed 1. The additions target three gaps: cognitive disabilities (underserved in 2.0/2.1), mobile/touch interactions, and focus visibility.

3.2.6 Consistent Help requires help mechanisms (contact info, chat, self-help) to appear in the same relative location across pages. Users with cognitive disabilities rely on spatial consistency to find help without searching.

<!-- Help in consistent footer position across all pages -->
<footer>
<nav aria-label="Help">
<a href="/contact">Contact Us</a>
<a href="/faq">FAQ</a>
<button id="chat-toggle">Chat Support</button>
</nav>
</footer>

3.3.7 Redundant Entry prohibits asking users to re-enter information they’ve already provided in the same session, unless re-entry is essential (security confirmation) or the previous value is no longer valid. Auto-population or selection from previous entries satisfies this.

<!-- Shipping address auto-fills billing if same -->
<fieldset>
<legend>Billing Address</legend>
<label>
<input type="checkbox" id="same-as-shipping" checked />
Same as shipping address
</label>
<!-- Fields auto-populate when checked -->
</fieldset>

2.4.11 Focus Not Obscured (Minimum) ensures focused elements aren’t entirely hidden by sticky headers, footers, or overlays. Partial obscuring is permitted at AA; full visibility requires AAA (2.4.12).

/* Ensure focused content isn't hidden by sticky header */
:focus {
scroll-margin-top: 80px; /* Height of sticky header + padding */
}
/* Or use scroll-padding on the scroll container */
html {
scroll-padding-top: 80px;
}

2.5.7 Dragging Movements requires a single-pointer alternative for any drag operation. Users with motor impairments may not be able to maintain pressure while moving.

<!-- Drag-to-reorder list with button alternatives -->
<li draggable="true">
<span>Item 1</span>
<button aria-label="Move Item 1 up" onclick="moveUp(this)">↑</button>
<button aria-label="Move Item 1 down" onclick="moveDown(this)">↓</button>
</li>

2.5.8 Target Size (Minimum) requires 24×24 CSS pixel minimum for pointer targets, with exceptions:

ExceptionDescription
SpacingUndersized target passes if 24px diameter circles centered on each target don’t overlap other targets
EquivalentAnother control on the same page meets the requirement
InlineText links within paragraphs are exempt
User agentBrowser-rendered controls (e.g., date picker calendar)
EssentialSize is legally required or information would be lost (maps)
/* Minimum touch target with spacing exception fallback */
.icon-button {
min-width: 24px;
min-height: 24px;
padding: 12px; /* Increases clickable area */
}
/* If 24px isn't achievable, ensure 24px spacing */
.small-button {
min-width: 20px;
min-height: 20px;
margin: 4px; /* Creates 24px circle clearance */
}

3.3.8 Accessible Authentication (Minimum) prohibits cognitive function tests (memory, transcription, puzzle-solving) as the sole authentication method. Alternatives must exist:

  • Copy-paste enabled for passwords (no blocking paste)
  • Password managers can auto-fill
  • OAuth/SSO (delegated authentication)
  • Biometrics or hardware tokens
  • Email/SMS codes (but not CAPTCHA that requires transcription)
<!-- Accessible login with password manager support -->
<form>
<label for="email">Email</label>
<input type="email" id="email" autocomplete="username" />
<label for="password">Password</label>
<input type="password" id="password" autocomplete="current-password" />
<!-- Alternative: passwordless -->
<button type="button" onclick="sendMagicLink()">Email me a login link</button>
</form>
  • 2.4.12 Focus Not Obscured (Enhanced): No part of focused element obscured (stricter than 2.4.11)
  • 2.4.13 Focus Appearance: Minimum 2px perimeter, 3:1 contrast between focused/unfocused states
  • 3.3.9 Accessible Authentication (Enhanced): No object recognition or personal content identification

WCAG 2.2 removed 4.1.1 Parsing because modern assistive technologies no longer parse HTML directly—they rely on browser accessibility APIs. Browsers now handle malformed HTML robustly, and issues that would have failed 4.1.1 (duplicate IDs, improper nesting) cause failures in other criteria (4.1.2 Name, Role, Value) when they actually impact users.

Migration note: If your test suite checks 4.1.1, don’t simply remove those tests. Duplicate IDs still fail 4.1.2 when they break accessible names. The change acknowledges that 4.1.1 was testing a mechanism (HTML validity) rather than an outcome (AT compatibility).

WCAG organizes all 86 success criteria under four principles. Understanding which principle a criterion belongs to clarifies what breaks when it fails.

PrincipleWhat FailsTypical Criteria
PerceivableContent cannot be perceived through any available senseText alternatives, captions, contrast, adaptable presentation
OperableUsers cannot interact with the interfaceKeyboard access, sufficient time, seizure prevention, navigation
UnderstandableUsers cannot comprehend content or predict behaviorReadable text, predictable operation, input assistance
RobustAssistive technologies cannot interpret contentValid markup, name/role/value, status messages

Perceivable failures create absolute barriers for specific disabilities—a missing alt attribute means blind users receive nothing. Operable failures often affect multiple groups: keyboard traps block keyboard-only users, motor-impaired users, and many screen reader users.

Understandable criteria address cognitive accessibility, the focus of WCAG 2.2’s additions. Cognitive disabilities affect ~15% of the population—more than any other disability category—yet were underserved in earlier WCAG versions.

Robust ensures AT compatibility. With 4.1.1 Parsing removed, the remaining Robust criteria focus on what browsers expose to the accessibility tree (4.1.2 Name, Role, Value) and how updates are communicated (4.1.3 Status Messages).

Semantic HTML provides most accessibility automatically. Native elements expose roles, states, and keyboard behavior to assistive technologies without JavaScript.

<header>
<nav aria-label="Main navigation">
<ul>
<li><a href="#main">Skip to main content</a></li>
<li><a href="/home">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
<main id="main">
<article>
<h1>Page Title</h1>
<section>
<h2>Section Heading</h2>
<p>Content goes here...</p>
</section>
</article>
</main>
<aside>
<h2>Related Information</h2>
</aside>
<footer>
<p>&copy; 2024 Your Website</p>
</footer>

Heading Hierarchy Implement a logical heading structure without skipping levels:

<h1>Main Page Title</h1>
<h2>Major Section</h2>
<h3>Subsection</h3>
<h3>Another Subsection</h3>
<h2>Another Major Section</h2>
<h3>Subsection</h3>

Language Declaration Always specify the document language and mark language changes:

<html lang="en">
<head>
<title>English Page</title>
</head>
<body>
<p>This is English text.</p>
<p lang="es">Este texto está en español.</p>
</body>
</html>

Forms are critical interaction points that require careful accessibility implementation:

Proper Labeling Every form control must have an accessible label:

<!-- Explicit labeling (preferred) -->
<label for="email">Email Address (required)</label>
<input type="email" id="email" name="email" required aria-describedby="email-error" />
<!-- Implicit labeling -->
<label>
Password
<input type="password" name="password" required />
</label>
<!-- Using aria-label when visual label isn't desired -->
<input type="search" name="search" aria-label="Search products" placeholder="Search..." />

Grouping Related Controls Use fieldset and legend for radio buttons and checkboxes:

<fieldset>
<legend>Preferred Contact Method</legend>
<input type="radio" id="email" name="contact" value="email" />
<label for="email">Email</label>
<input type="radio" id="phone" name="contact" value="phone" />
<label for="phone">Phone</label>
<input type="radio" id="mail" name="contact" value="mail" />
<label for="mail">Mail</label>
</fieldset>

Error Handling and Validation Provide clear, helpful error messages:

<label for="username">Username (required)</label>
<input type="text" id="username" name="username" required aria-describedby="username-error" aria-invalid="true" />
<div id="username-error" role="alert">Username is required and must be at least 3 characters long.</div>

Instructions and Help Text Use aria-describedby to associate help text with form controls:

<label for="password">Password</label>
<input type="password" id="password" name="password" aria-describedby="password-help" required />
<div id="password-help">Password must be at least 8 characters long and contain at least one number.</div>

Alternative Text for Images Provide meaningful alt text that serves the same purpose as the image:

<!-- Informative image -->
<img src="sales-chart.png" alt="Sales increased 25% from January to March 2024" />
<!-- Decorative image -->
<img src="decorative-border.png" alt="" role="presentation" />
<!-- Functional image (button) -->
<button type="submit">
<img src="search-icon.png" alt="Search" />
</button>
<!-- Complex image with longer description -->
<img src="complex-chart.png" alt="Quarterly sales data" aria-describedby="chart-desc" />
<div id="chart-desc">
Detailed description: Sales data shows Q1 at $100k, Q2 at $150k, Q3 at $175k, and Q4 at $200k, representing steady
growth throughout the year.
</div>

Video and Audio Accessibility Multimedia content requires multiple accessibility features:

<!-- Video with captions and audio description -->
<video controls>
<source src="training-video.mp4" type="video/mp4" />
<track kind="captions" src="captions.vtt" srclang="en" label="English captions" />
<track kind="descriptions" src="descriptions.vtt" srclang="en" label="Audio descriptions" />
<p>Your browser doesn't support video. <a href="transcript.html">Read the transcript</a></p>
</video>
<!-- Audio-only content -->
<audio controls>
<source src="podcast.mp3" type="audio/mpeg" />
<p>Your browser doesn't support audio. <a href="transcript.html">Read the transcript</a></p>
</audio>
<p><a href="podcast-transcript.txt">Download transcript</a></p>

Buttons and Links Ensure interactive elements have clear purposes and are keyboard accessible:

<!-- Descriptive button text -->
<button type="submit">Submit Contact Form</button>
<!-- Button with icon needs accessible text -->
<button type="button" aria-label="Close dialog">
<svg aria-hidden="true">...</svg>
</button>
<!-- Link with clear destination -->
<a href="/products/laptops">View all laptop models</a>
<!-- Link opening new window/tab -->
<a href="/terms.pdf" target="_blank"> Terms of Service <span class="sr-only">(opens in new tab)</span> </a>

Custom Interactive Components When creating custom widgets, use ARIA roles, properties, and states:

<!-- Custom dropdown menu -->
<div class="dropdown">
<button aria-haspopup="true" aria-expanded="false" id="menu-button">Options</button>
<ul role="menu" aria-labelledby="menu-button" hidden>
<li role="menuitem"><a href="/option1">Option 1</a></li>
<li role="menuitem"><a href="/option2">Option 2</a></li>
<li role="menuitem"><a href="/option3">Option 3</a></li>
</ul>
</div>
<!-- Custom tab interface -->
<div role="tablist" aria-label="Content sections">
<button role="tab" aria-selected="true" aria-controls="panel1" id="tab1">Section 1</button>
<button role="tab" aria-selected="false" aria-controls="panel2" id="tab2">Section 2</button>
</div>
<div role="tabpanel" id="panel1" aria-labelledby="tab1">
<h2>Section 1 Content</h2>
<p>Content for the first section...</p>
</div>
<div role="tabpanel" id="panel2" aria-labelledby="tab2" hidden>
<h2>Section 2 Content</h2>
<p>Content for the second section...</p>
</div>

Color Contrast Requirements Ensure sufficient contrast ratios for all text and UI components:

  • Normal text: Minimum 4.5:1 contrast ratio (WCAG AA)
  • Large text (18pt+ or 14pt+ bold): Minimum 3:1 contrast ratio
  • UI components: Minimum 3:1 contrast ratio for borders, icons, and focus indicators

Color-Independent Information Never rely solely on color to convey information:

<!-- Bad: Only color indicates required field -->
<label style="color: red;">Email</label>
<input type="email" name="email" />
<!-- Good: Color plus text/symbol indicator -->
<label>Email <span class="required" aria-label="required">*</span></label>
<input type="email" name="email" required />
<!-- Good: Error states with multiple indicators -->
<label for="email">Email</label>
<input type="email" id="email" name="email" aria-invalid="true" class="error" aria-describedby="email-error" />
<div id="email-error" class="error-message" role="alert">⚠️ Please enter a valid email address</div>

Focus Indicators Provide clear, visible focus indicators for all interactive elements:

/* Ensure focus indicators are visible */
button:focus,
input:focus,
select:focus,
textarea:focus,
a:focus {
outline: 2px solid #005fcc;
outline-offset: 2px;
}
/* Custom focus styles that meet contrast requirements */
.custom-button:focus {
box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.5);
outline: 2px solid #005fcc;
}

Focus Trapping

Modals must trap focus—users shouldn’t be able to Tab out of the modal to content behind it. The pattern: track first/last focusable elements, intercept Tab at boundaries.

focus-trap.js
3 collapsed lines
function trapFocus(element) {
const focusable = element.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')
const first = focusable[0]
const last = focusable[focusable.length - 1]
element.addEventListener("keydown", (e) => {
if (e.key !== "Tab") return
if (e.shiftKey && document.activeElement === first) {
last.focus()
e.preventDefault()
} else if (!e.shiftKey && document.activeElement === last) {
first.focus()
e.preventDefault()
3 collapsed lines
}
})
}

SPAs and dynamic content require explicit accessibility management that static pages handle automatically.

Live Regions announce changes to screen readers without moving focus:

<!-- polite: announced when user is idle; assertive: immediate interruption -->
<div id="status" role="status" aria-live="polite"></div>
<div id="alerts" role="alert" aria-live="assertive"></div>

SPA Route Changes must update document title and move focus:

spa-navigation.js
2 collapsed lines
function navigateToPage(pageContent, pageTitle) {
document.getElementById("main-content").innerHTML = pageContent
document.title = pageTitle
// Move focus to main content, not page top
const main = document.getElementById("main-content")
main.setAttribute("tabindex", "-1")
main.focus()
}

Modal Focus requires: (1) trap focus inside, (2) return focus on close.

modal-focus.js
2 collapsed lines
function openModal(modal) {
const previousFocus = document.activeElement
modal.removeAttribute("hidden")
modal.querySelector("button, [href], input")?.focus()
trapFocus(modal)
modal.addEventListener("close", () => previousFocus.focus(), { once: true })
1 collapsed line
}

Automated tools detect ~57% of individual accessibility issues (Deque 2024 study across 13,000+ pages) but only ~35% of WCAG success criteria are fully automatable. The remaining issues require manual testing—there’s no shortcut.

What Automation CatchesWhat Requires Manual Testing
Missing alt text (presence, not quality)Alt text accuracy and context
Color contrast ratiosColor-only information conveying
Missing form labelsLabel clarity and helpfulness
Duplicate IDsLogical reading order
ARIA attribute validityARIA usage correctness
Heading structureContent organization

Contrast issues alone account for ~30% of detected issues—highly automatable but only part of the picture.

axe-core powers most accessibility testing. Use @axe-core/playwright or cypress-axe for CI integration. Configure for WCAG 2.2 AA:

playwright.config.js
5 collapsed lines
// Configure axe for WCAG 2.2 AA
const axeConfig = {
runOnly: {
type: "tag",
values: ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22aa"],
},
}

Pa11y for CLI/CI pipelines—respects robots.txt and handles JavaScript-rendered content.

Lighthouse provides quick audits but uses a subset of axe-core rules. Use for initial scans, not compliance verification.

Test with at least one screen reader per platform your users access:

PlatformScreen ReaderMarket ShareNotes
WindowsNVDA~40%Free, open-source, most common for testing
WindowsJAWS~30%Commercial, enterprise standard
macOS/iOSVoiceOver~15%Built-in, required for Apple ecosystem
AndroidTalkBack~10%Built-in, required for Android

Focus testing on: navigation flow, form completion, dynamic content updates, and error recovery.

Integrating accessibility testing into your continuous integration and deployment pipeline ensures that accessibility issues are caught early and consistently.

GitHub Actions Example:

.github/workflows/accessibility.yml
22 collapsed lines
name: Accessibility Testing
on: [push, pull_request]
jobs:
accessibility-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: "16"
- name: Install dependencies
run: npm install
- name: Build application
run: npm run build
- name: Start application
run: npm start &
- name: Wait for application to start
run: sleep 30
- name: Run Pa11y tests
run: |
npx pa11y-ci --sitemap http://localhost:3000/sitemap.xml
- name: Run axe tests with Cypress
run: npx cypress run --spec "cypress/integration/accessibility.spec.js"

Cypress with axe-core:

cypress/integration/accessibility.spec.js
6 collapsed lines
// cypress/integration/accessibility.spec.js
describe("Accessibility Tests", () => {
beforeEach(() => {
cy.visit("/")
cy.injectAxe()
})
it("Has no accessibility violations on home page", () => {
cy.checkA11y()
})
it("Has no accessibility violations on contact form", () => {
cy.visit("/contact")
cy.checkA11y()
})
it("Has no accessibility violations after form interaction", () => {
cy.visit("/contact")
cy.get("#name").type("Test User")
cy.get("#email").type("test@example.com")
cy.checkA11y()
})
})

Playwright with axe-core:

tests/accessibility.spec.js
3 collapsed lines
const { test, expect } = require("@playwright/test")
const AxeBuilder = require("@axe-core/playwright")
test("Homepage accessibility", async ({ page }) => {
await page.goto("/")
const accessibilityScanResults = await new AxeBuilder({ page }).analyze()
expect(accessibilityScanResults.violations).toEqual([])
})

Implement accessibility quality gates that fail builds when critical issues are found:

.github/workflows/accessibility.yml
- name: Run accessibility tests
run: |
npx pa11y-ci --threshold 5 http://localhost:3000
continue-on-error: false
- name: Generate accessibility report
run: |
npx pa11y-ci --reporter json > accessibility-report.json
- name: Upload accessibility report
uses: actions/upload-artifact@v2
with:
name: accessibility-report
path: accessibility-report.json

Shadow DOM creates accessibility challenges because ARIA attributes don’t penetrate the shadow boundary and screen readers may not correctly associate labels across boundaries.

Key patterns:

web-component-a11y.js
8 collapsed lines
class AccessibleComponent extends HTMLElement {
static get observedAttributes() {
return ["aria-label", "aria-describedby"]
}
connectedCallback() {
// Forward ARIA from host to shadow root element
const button = this.shadowRoot.querySelector("button")
for (const attr of AccessibleComponent.observedAttributes) {
if (this.hasAttribute(attr)) {
button.setAttribute(attr, this.getAttribute(attr))
}
}
}
attributeChangedCallback(name, oldVal, newVal) {
// Keep shadow DOM in sync with host attributes
this.shadowRoot?.querySelector("button")?.setAttribute(name, newVal)
}
}

Edge cases:

  • aria-labelledby and aria-describedby cannot reference IDs outside the shadow root
  • Use aria-label instead, or expose a <slot> for labeling content
  • Focus delegation with delegatesFocus: true in attachShadow() options

Accessibility law has shifted from guidance to enforcement. Know your obligations.

ADA Title II (state/local government): DOJ’s 2024 rule mandates WCAG 2.1 AA by April 2026 for entities with 50,000+ population, April 2027 for smaller entities.

ADA Title III (private sector): No explicit WCAG version in regulation, but courts consistently apply WCAG 2.1 AA as the standard. The “places of public accommodation” interpretation covers websites—Domino’s v. Robles (2019) confirmed this.

Section 508 (federal government): Still references WCAG 2.0 AA via the Revised 508 Standards (2017). Refresh expected but not yet scheduled.

European Accessibility Act (EAA): Enforced since June 28, 2025. Applies to businesses selling to EU customers regardless of where the business is located. Currently requires WCAG 2.1 AA via EN 301 549; update to include WCAG 2.2 in progress.

Web Accessibility Directive: Applies to public sector bodies. Required WCAG 2.1 AA since September 2020.

Practical note: Target WCAG 2.2 AA even if current laws reference 2.1. The delta is 6 criteria, and demonstrating awareness of current standards strengthens legal defensibility.

  • HTML5 semantic elements and document structure
  • CSS layout and responsive design fundamentals
  • JavaScript event handling and DOM manipulation
  • Basic understanding of assistive technology categories (screen readers, switch devices, voice control)
  • WCAG 2.2 contains 86 success criteria across three levels (A: 32, AA: +24, AAA: +30)
  • New in 2.2: 9 criteria targeting cognitive accessibility, motor accessibility, and focus visibility; 4.1.1 Parsing removed
  • Legal compliance requires WCAG 2.1 AA minimum (US ADA, EU EAA); target 2.2 AA for future-proofing
  • Automated testing catches ~57% of individual issues but only ~35% of criteria; manual testing is mandatory
  • Semantic HTML provides most accessibility automatically; ARIA supplements for custom widgets
  • Focus management in SPAs and modals is the most common source of regressions
  • a11y: Numeronym for “accessibility” (a + 11 letters + y)
  • AT: Assistive Technology—software/hardware enabling people with disabilities to use computers
  • POUR: Perceivable, Operable, Understandable, Robust—WCAG’s organizing principles
  • ARIA: Accessible Rich Internet Applications—W3C specification for enhancing HTML semantics
  • Live Region: ARIA mechanism for announcing dynamic content changes to screen readers
  • Focus Trap: Containing keyboard focus within a component (intentional in modals, a bug elsewhere)

Specifications (Primary)

Official Documentation

Testing Tools

Legal

Read more

  • Previous

    Accessibility Testing and Tooling Workflow

    Web Foundations / Accessibility Standards 14 min read

    A practical workflow for automated and manual accessibility testing, covering tool selection, CI/CD integration, and testing strategies. Automated testing catches approximately 57% of accessibility issues (Deque, 2021)—the remaining 43% requires keyboard navigation testing, screen reader verification, and subjective judgment about content quality. This guide covers how to build a testing strategy that maximizes automated coverage while establishing the manual testing practices that no tool can replace.

  • Next

    Heaps and Priority Queues: Internals, Trade-offs, and When Theory Breaks Down

    Programming & Patterns / Data Structures 19 min read

    Heaps provide the fundamental abstraction for “give me the most important thing next” in O(log n) time. Priority queues—the abstract interface—power task schedulers, shortest-path algorithms, and event-driven simulations. Binary heaps dominate in practice not because they’re theoretically optimal, but because array storage exploits cache locality. Understanding the gap between textbook complexity and real-world performance reveals when to use standard libraries, when to roll your own, and when the “better” algorithm is actually worse.