SEO & AI Engine Optimization Framework · May 2026

Accessibility: WCAG 2.2, Section 508, accessible-by-default patterns

A comprehensive installation and audit reference for accessibility as a ranking and citation discipline. In 2026 accessibility is no longer a compliance afterthought. It is a measurable ranking…

WCAG 2.2 Conformance, WCAG 3.0 Preview, Semantic HTML for AI Parsing, Screen Reader Optimization, Keyboard Navigation, ARIA Implementation, Legal Exposure under ADA/EAA/AODA/Section 508, and the 2026 Convergence of Accessibility as a Measurable SEO and AI Citation Signal

A comprehensive installation and audit reference for accessibility as a ranking and citation discipline. In 2026 accessibility is no longer a compliance afterthought. It is a measurable ranking factor and a strong AI citation signal because synthesis engines preferentially extract from well structured semantic markup. The same heading hierarchy, landmark roles, ARIA labels, and semantic elements that screen readers consume are what AI extraction layers parse. An accessible site is an AI citable site.

Cross stack implementation note. The code samples in this framework are written in plain HTML for clarity. For React, Vue, Svelte, Next.js, Nuxt, SvelteKit, Astro, Hugo, 11ty, Remix, WordPress, Shopify, and Webflow equivalents see framework-cross-stack-implementation.md. For pure client rendered SPAs see framework-react.md. For Tailwind specific concerns see framework-tailwind.md.


1. Document Purpose

Accessibility in 2026 produces three compounding effects on a web property:

  1. Compliance protection. Reduces ADA Title III, European Accessibility Act, AODA, Section 508, and California Unruh Act exposure. Seyfarth Shaw 2025 federal lawsuit report counted 4,605 federal ADA Title III website filings in calendar year 2024. Settlements typically run 8,000 to 75,000 USD per case.
  2. Search and assistive technology overlap. Screen readers and Googlebot both parse the same semantic markup. A document outline a screen reader can navigate is a document outline Googlebot can index for ranking and Gemini can extract for AI Overview citation.
  3. Citation lift on AI surfaces. Surfer SEO October 2025 study of 41,200 URLs found pages with explicit ARIA landmark roles received 23 percent more AI Overview citations than topically equivalent pages with <div> based scaffolding. Princeton GEO study (SIGKDD 2024) attributed similar lift to clean heading hierarchies.

Three independent dimensions converge:

1.1 Three Operating Modes

Mode A, Install. Bring a new build to WCAG 2.2 AA conformance during development. Mode B, Audit. Evaluate an existing site for conformance and legal exposure. Mode C, Remediation. Audit first, then install for failing items in priority order.

1.2 Required Tools

1.3 Relationship to Neighboring Frameworks

The broader UX layer lives in framework-uxseo.md. Performance and Core Web Vitals in framework-pageexperience.md. Mobile concerns in framework-mobileseo.md. Schema graph patterns in framework-schema.md. E-E-A-T credibility in framework-eeat.md. AI citation mechanics in framework-aicitations.md.


2. Client Variables Intake

# ACCESSIBILITY FRAMEWORK CLIENT VARIABLES

# --- Business and Site Identity (REQUIRED) ---
business_name: ""
primary_domain: ""
jurisdiction_primary: ""             # "us_only", "us_plus_eu", "us_plus_canada", "global"
public_sector_or_federal_contractor: false
ymyl_classification: ""              # "full_ymyl", "partial_ymyl", "lite_ymyl", "non_ymyl"

# --- Conformance Target (REQUIRED) ---
wcag_target_level: "AA"              # "A", "AA", "AAA"
wcag_version: "2.2"
accessibility_statement_published: false
last_independent_audit_date: ""

# --- Current State (REQUIRED) ---
lighthouse_accessibility_score: 0
axe_violations_critical: 0
axe_violations_serious: 0
wave_errors: 0
pa11y_ci_pass: false

# --- Semantic Markup Posture (REQUIRED) ---
semantic_landmarks_present: false
single_h1_per_page: false
heading_hierarchy_sequential: false
skip_link_present: false
focus_visible_implemented: false

# --- Form Accessibility (REQUIRED if forms present) ---
all_inputs_have_labels: false
autocomplete_attributes_present: false
fieldset_legend_for_groups: false
error_messages_associated: false

# --- Color and Contrast (REQUIRED) ---
text_contrast_4_5_to_1_minimum: false
ui_component_contrast_3_to_1: false

# --- Motion (REQUIRED) ---
prefers_reduced_motion_respected: false
no_autoplay_video_with_audio: false
no_flashing_above_3hz: false

# --- Testing Cadence (REQUIRED) ---
automated_ci_on_every_deploy: false
manual_keyboard_test_cadence: ""
manual_screen_reader_test_cadence: ""

Sites with public_sector_or_federal_contractor: true route to Section 508 (which references WCAG 2.0 AA technical baseline with agency procurement language uplifting toward 2.2). Sites with EU jurisdiction route to EAA conformance, harmonized via EN 301 549.


3. The 2026 Legal Landscape

3.1 ADA Title III in the United States

Federal courts have applied ADA Title III to commercial websites since the early 2010s. The Seyfarth Shaw 2025 federal accessibility lawsuit report counted 4,605 federal ADA Title III website filings in calendar year 2024 across an estimated 1,800 unique law firms. New York Southern District, New York Eastern District, and Florida Southern District remain the most active jurisdictions. California state court Unruh Act filings add a parallel volume.

Settlement economics in 2026:

Case profile Typical settlement range
First filing, small business, remediation commitment 5,000 to 15,000 USD
First filing, mid market, complex remediation 15,000 to 50,000 USD
Repeat defendant or enterprise tier 50,000 to 250,000 USD
Class action or DOJ enforcement 500,000 USD and above

Courts most commonly reference WCAG 2.1 AA. WCAG 2.2 was published as W3C recommendation October 2023 and is now widely accepted as the operational target for new builds.

3.2 European Accessibility Act, June 2025

The European Accessibility Act (Directive 2019/882) took full effect across EU member states on June 28, 2025. Scope covers e-commerce, banking, e-books, ticketing, transport, telecommunications, computing hardware, ATMs, and consumer facing digital products. Harmonized technical standard EN 301 549 references WCAG 2.1 AA. US sites selling to EU consumers above the de minimis micro enterprise threshold must conform.

3.3 Section 508 Federal Requirement

Section 508 requires federal agencies and contractors to ensure ICT accessibility. Revised 508 Standards (effective January 18, 2018) reference WCAG 2.0 AA. Agency procurement language increasingly specifies WCAG 2.2 AA. Federal contractors failing VPAT or ACR review face procurement disqualification.

3.4 Ontario AODA

Web accessibility requirements binding on private sector organizations of 50 plus employees since January 1, 2021 (WCAG 2.0 AA). Compliance reporting continues through 2026. Out of scope for organizations with no Ontario nexus.

3.5 California Unruh Civil Rights Act

The Unruh Act extends ADA Title III protections to in state businesses regardless of physical presence. Statutory damages of 4,000 USD per violation plus attorney fees. Sites with substantial California traffic should treat WCAG 2.2 AA as the operational target.

3.6 Defense Posture

Three artifacts materially shift settlement leverage:

  1. Published accessibility statement at /accessibility/ listing target conformance level, accessibility contact, most recent audit date, and remediation roadmap.
  2. Independent third party audit dated within the prior 12 months, performed by CPACC or WAS certified auditor, findings remediated or in documented remediation.
  3. Active remediation cadence with documented commits, deploy logs, and ticket queue showing ongoing work.

4. WCAG 2.2 Coverage

WCAG 2.2 published October 5, 2023 is the current W3C recommendation. Adds nine new success criteria to WCAG 2.1, removes one (4.1.1 Parsing), clarifies several existing criteria. Conformance levels A, AA, AAA stack. Target is AA.

4.1 The Four POUR Principles

4.2 Conformance Levels

Level Description Target
A Minimum. A site failing A is functionally unusable for some user classes. Required floor.
AA Standard. The level most courts, regulators, and procurement reference. Yes, operational target.
AAA Enhanced. Higher contrast, exhaustive captioning, sign language, no time limits. Aspirational where reasonable.

4.3 The New Criteria in WCAG 2.2

Nine criteria added in 2.2, plus four carried from 2.1 that remain operationally relevant:

  1. 2.4.11 Focus Not Obscured (Minimum) AA. Focused element not entirely hidden by author content.
  2. 2.4.12 Focus Not Obscured (Enhanced) AAA. No part of focused element hidden.
  3. 2.4.13 Focus Appearance AAA. Focus indicator meets minimum size and contrast.
  4. 2.5.7 Dragging Movements AA. Dragging functionality available via single pointer alternative.
  5. 2.5.8 Target Size (Minimum) AA. Pointer targets at least 24 by 24 CSS pixels. Framework still recommends 44x44 mobile UX target for primary targets.
  6. 3.2.6 Consistent Help A. Help mechanisms appear in same relative order across pages.
  7. 3.3.7 Redundant Entry A. Previously entered information auto populated or selectable.
  8. 3.3.8 Accessible Authentication (Minimum) AA. Authentication does not require cognitive function test unless alternative available.
  9. 3.3.9 Accessible Authentication (Enhanced) AAA. No cognitive function test at all.

Carried from 2.1:

  1. 1.3.4 Orientation AA. Content does not restrict view to single orientation.
  2. 1.3.5 Identify Input Purpose AA. Input purpose programmatically determined via autocomplete.
  3. 1.4.10 Reflow AA. Content displays at 320 CSS pixel width without two dimensional scrolling.
  4. 1.4.11 Non text Contrast AA. UI components and graphical objects at least 3 to 1 contrast.

4.4 The Removed Criterion: 4.1.1 Parsing

WCAG 2.2 marks 4.1.1 Parsing obsolete. Modern parsers handle malformed HTML reliably. Still write well formed HTML and avoid duplicate IDs (they break label-for pairing and ARIA references), but parsing is no longer a separate audit point.

4.5 Critical Criteria

A site failing any of these eight functionally fails both WCAG 2.2 AA and AI citation eligibility on substantial query classes:

1.1.1 Non-text Content, 1.3.1 Info and Relationships, 1.3.5 Identify Input Purpose, 1.4.3 Contrast Minimum, 2.1.1 Keyboard, 2.4.6 Headings and Labels, 2.4.7 Focus Visible, 3.3.2 Labels or Instructions.


5. WCAG 3.0 Preview

W3C published WCAG 3.0 working draft updates through 2024 and 2025. Latest public working draft dated July 2024 with subsequent editor drafts through Q1 2026. Not yet a published recommendation. Major shifts:

5.1 Scoring Model

WCAG 2.x conformance is binary per success criterion. WCAG 3.0 proposes a 0 to 100 page level score combining weighted outcomes. Pages can be bronze, silver, or gold conformant. Bronze maps approximately to WCAG 2.2 AA.

5.2 Expanded Scope

Working draft expands to native mobile apps, immersive XR, voice user interfaces, and conversational agents.

5.3 Advanced Perceptual Contrast Algorithm

APCA models perceived contrast more accurately than the WCAG 2 relative luminance based algorithm, especially for dark mode and large text. APCA scores range different from WCAG 2.x ratios. Production target stays WCAG 2.2 4.5 to 1 until 3.0 reaches recommendation.

5.4 Outcome Based Criteria

WCAG 3.0 outcomes describe what users can do rather than technical conformance. Improves clarity but lengthens assessment.

5.5 Operational Posture

Target WCAG 2.2 AA. Document substantive accessibility work that maps to WCAG 3.0 outcomes (cognitive accessibility, plain language, consistent help). When 3.0 reaches recommendation, gap analysis is additive.


6. Semantic HTML and AI Parsing

Semantic HTML is the substrate accessibility layer and the substrate AI parsing layer. The same elements screen readers announce as landmarks, sections, headings, and controls are the elements AI engines parse for content structure.

6.1 Why Semantic HTML Lifts Both Surfaces

Surfer SEO October 2025 study of 41,200 URLs comparing pages with semantic landmark roles against pages with <div> based scaffolding, controlling for topical relevance and link profile, found 23 percent higher AI Overview citation rate on the semantic cohort. Mechanism: reading mode bots parse by structure. A page announcing main content via <main> is reliably extracted. A page where the engine must infer main content from layout heuristics is not.

6.2 The Landmark Pattern

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Page Title</title>
</head>
<body>
  <a href="#main-content" class="skip-link">Skip to main content</a>

  <header>
    <a href="/" aria-label="Home"><img src="/logo.svg" alt="Business Name"></a>
    <nav aria-label="Main navigation">
      <ul>
        <li><a href="/services/">Services</a></li>
        <li><a href="/about/">About</a></li>
        <li><a href="/contact/">Contact</a></li>
      </ul>
    </nav>
  </header>

  <main id="main-content">
    <article>
      <header>
        <h1>Page Title Matching Title Tag</h1>
        <p class="lede">40 to 75 word lede answering the page's target query.</p>
      </header>

      <section aria-labelledby="section-1-heading">
        <h2 id="section-1-heading">Section heading</h2>
        <p>Answer first paragraph addressing the H2 question.</p>
      </section>
    </article>

    <aside aria-labelledby="related-heading">
      <h2 id="related-heading">Related resources</h2>
    </aside>
  </main>

  <footer>
    <p>Footer content.</p>
  </footer>
</body>
</html>

Single <main> per page. Single <h1> per page. <nav> carries aria-label when multiple nav landmarks exist. <section> carries aria-labelledby referencing its own heading id.

6.3 Semantic Replacements

Anti pattern Semantic replacement
<div class="header"> <header>
<div class="nav"> <nav>
<div class="main"> <main>
<div class="footer"> <footer>
<div class="sidebar"> <aside>
<div class="article"> <article>
<p style="font-size:32px;font-weight:bold;"> <h1>, <h2>, etc.
<div onclick> <button>
Series of <div> items <ul> or <ol>
<table> for layout CSS grid or flexbox
<div> for tabular data <table> with <thead>, <tbody>, <th scope>

6.4 The First Byte Test

Every semantic markup commitment must survive the curl test:

curl -A "GPTBot" -s https://example.com/page | grep -E "<main|<nav|<h1|<header|<footer"

If the landmarks are not in first byte HTML, they are invisible to AI engines regardless of how they render in a browser. Client side hydrated markup fails reading mode parsing the same way it fails screen reader announcement on AT that does not wait for hydration.


7. Heading Hierarchy and Document Outline

Heading hierarchy is one of the highest leverage accessibility signals and one of the most direct AI citation signals. AI Overview snippets frequently quote H2 or H3 boundary content.

7.1 The Rules

  1. One H1 per page. Announces primary topic, matches visible page title, closely related to title tag.
  2. Sequential descent. H1 to H2, H2 to H3, H3 to H4. No skipping.
  3. Semantic match between heading and content. Text under heading addresses what heading promises.
  4. No heading tags for visual styling. Use CSS for size, heading levels for meaning.
  5. Headings describe section content, not position. H2 "Section 1" fails. H2 "How quarterly estimated taxes are calculated" passes.

7.2 The Outline Pattern

<main id="main-content">
  <article>
    <header>
      <h1>How to Pay Quarterly Estimated Taxes in 2026</h1>
      <p class="lede">...</p>
    </header>

    <section aria-labelledby="when-due">
      <h2 id="when-due">When are quarterly taxes due in 2026</h2>
      <p>Direct answer paragraph.</p>
    </section>

    <section aria-labelledby="how-to-pay">
      <h2 id="how-to-pay">How to pay quarterly taxes</h2>
      <p>Direct answer paragraph.</p>

      <section aria-labelledby="irs-direct-pay">
        <h3 id="irs-direct-pay">IRS Direct Pay</h3>
      </section>

      <section aria-labelledby="eftps">
        <h3 id="eftps">EFTPS enrollment</h3>
      </section>
    </section>
  </article>
</main>

7.3 Tooling

HeadingsMap Chrome extension visualizes the outline. Lighthouse flags missing H1 and out of order headings. Manual audit: navigate the page in NVDA or VoiceOver using H key and verify announced sequence.

7.4 H1 and Title Tag Relationship

<title> and <h1> are not required to match exactly. Title for SERP and browser tab (60 character limit, query match, brand). H1 for on page clarity (descriptive, complete sentence acceptable). Both communicate the same topic in different framings.

7.5 AI Overview Citation Boundary

AI Overview snippets often quote the first sentence under an H2 or H3 boundary. The answer first pattern under every H2 (40 to 75 word direct answer) gives the synthesis engine a citeable extraction surface. See framework-aioverviews.md Section 6.3.


8. Image Accessibility

Image accessibility intersects with image SEO. Comprehensive guidance in framework-imageseo.md. This section covers accessibility specific patterns.

8.1 Alt Text Writing Protocol

Alt text describes content function, not appearance. A photograph of an operator at a press in a safety article is "Operator wearing required PPE while loading material into industrial press" not "Photo of person at machine."

Categories:

alt_text_categories:

  informational:
    pattern: "Describe what the image conveys in context"
    good: 'alt="Bar chart showing 40 percent revenue growth from Q1 to Q4 2026"'
    bad: 'alt="Chart"'

  decorative:
    pattern: 'Empty alt attribute alt=""'
    example: '<img alt="" src="/divider.svg" role="presentation">'

  functional:
    pattern: "Describe function not appearance"
    good: '<img alt="Search" src="/search-icon.svg">'
    bad: '<img alt="Magnifying glass icon" src="/search-icon.svg">'

  complex:
    pattern: "Alt text plus extended description nearby"
    example: |
      <img alt="14 tier framework diagram, full description below" src="/diagram.svg">
      <p>The framework is organized in 14 tiers ascending...</p>

  logos:
    pattern: "Business name as alt"
    example: '<img alt="ThatDeveloperGuy" src="/logo.svg">'

8.2 Anti Patterns

<!-- Missing alt, WCAG 1.1.1 failure -->
<img src="/hero.jpg">

<!-- Redundant phrasing, screen readers already announce as image -->
<img alt="Image of a dog playing fetch" src="/dog.jpg">

<!-- Filename as alt -->
<img alt="IMG_0432.jpg" src="/IMG_0432.jpg">

<!-- Empty alt on informational image -->
<img alt="" src="/important-chart.png">

<!-- Alt text on decorative image, adds noise -->
<img alt="Decorative swirl element" src="/swirl.svg">

8.3 SVG Accessibility

<!-- Inline SVG with title and desc -->
<svg viewBox="0 0 100 100" role="img" aria-labelledby="chart-title chart-desc">
  <title id="chart-title">Q1 to Q4 Revenue Growth</title>
  <desc id="chart-desc">Bar chart showing 40 percent growth across three product lines.</desc>
  <rect x="10" y="50" width="20" height="40" fill="#4a90e2"></rect>
</svg>

<!-- Decorative inline SVG -->
<svg viewBox="0 0 100 100" role="presentation" aria-hidden="true">
  <path d="..."></path>
</svg>

<!-- SVG icon inside a button -->
<button aria-label="Close dialog">
  <svg viewBox="0 0 24 24" aria-hidden="true"><path d="..."></path></svg>
</button>

8.4 Background Images

CSS background images have no alt attributes. If a background image conveys meaning, the meaning must be available in HTML text. Never put meaningful content in CSS background images alone.

8.5 Figure and Figcaption

<figure>
  <img src="/process-diagram.svg" alt="Five step content first publishing process">
  <figcaption>Figure 1. Publishing process from intake through validation.</figcaption>
</figure>

Screen readers announce the figure landmark and read the caption. AI engines parse the figure as a content block with the caption as metadata.

8.6 AI Engine Image Parsing

Gemini 3 Pro and ChatGPT 5 extract content from alt text, surrounding text, captions, and figure markup. Descriptive alt text is consumed by the synthesis engine. A page with thoughtful alt text has more extractable surface area.


9. Form Accessibility

Forms are high stakes accessibility points and high stakes conversion points. The same patterns that make forms accessible lift completion rates. Comprehensive form optimization in framework-formoptimization.md.

9.1 Label For Pairing

<!-- Explicit label, preferred -->
<label for="email">Email address</label>
<input type="email" id="email" name="email" autocomplete="email" required>

<!-- Implicit label, acceptable -->
<label>
  Email address
  <input type="email" name="email" autocomplete="email" required>
</label>

<!-- Anti pattern: placeholder as label, fails WCAG 3.3.2 -->
<input type="email" placeholder="Email" name="email">

9.2 Autocomplete Attributes

WCAG 2.1 1.3.5 Identify Input Purpose requires autocomplete attributes on fields that collect user information. Also enables browser autofill which lifts completion.

<form>
  <label for="given-name">First name</label>
  <input type="text" id="given-name" name="given-name" autocomplete="given-name">

  <label for="family-name">Last name</label>
  <input type="text" id="family-name" name="family-name" autocomplete="family-name">

  <label for="email">Email</label>
  <input type="email" id="email" name="email" autocomplete="email">

  <label for="tel">Phone</label>
  <input type="tel" id="tel" name="tel" autocomplete="tel">

  <label for="street">Street address</label>
  <input type="text" id="street" name="street" autocomplete="street-address">

  <label for="city">City</label>
  <input type="text" id="city" name="city" autocomplete="address-level2">

  <label for="state">State</label>
  <input type="text" id="state" name="state" autocomplete="address-level1">

  <label for="postal">Postal code</label>
  <input type="text" id="postal" name="postal" autocomplete="postal-code">

  <label for="org">Organization</label>
  <input type="text" id="org" name="org" autocomplete="organization">
</form>

9.3 Error Messaging

<label for="email">Email</label>
<input
  type="email"
  id="email"
  name="email"
  autocomplete="email"
  required
  aria-required="true"
  aria-invalid="false"
  aria-describedby="email-help email-error">
<span id="email-help" class="help-text">We'll never share your email.</span>
<span id="email-error" role="alert" class="error-text" hidden>
  Please enter a valid email address.
</span>

On validation failure:

const input = document.getElementById('email');
const error = document.getElementById('email-error');

input.setAttribute('aria-invalid', 'true');
error.hidden = false;
error.textContent = 'Please enter a valid email address.';

Screen reader announces error when role="alert" becomes visible.

9.4 Fieldset and Legend

<fieldset>
  <legend>Shipping address</legend>
  <label for="ship-street">Street</label>
  <input type="text" id="ship-street" name="ship-street" autocomplete="shipping street-address">
  <label for="ship-city">City</label>
  <input type="text" id="ship-city" name="ship-city" autocomplete="shipping address-level2">
</fieldset>

<fieldset>
  <legend>Preferred contact method</legend>
  <input type="radio" id="contact-email" name="contact" value="email">
  <label for="contact-email">Email</label>
  <input type="radio" id="contact-phone" name="contact" value="phone">
  <label for="contact-phone">Phone</label>
</fieldset>

9.5 Required Indicators

<label for="name">
  Full name <span class="required-indicator" aria-hidden="true">*</span>
  <span class="visually-hidden">(required)</span>
</label>
<input type="text" id="name" name="name" autocomplete="name" required aria-required="true">

<style>
  .visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
</style>

9.6 Honeypot and CAPTCHA Tradeoff

CAPTCHA is hostile to screen reader users and keyboard only users. Honeypot fields (hidden input expected to remain empty, indicating bot if filled) are accessible because real users never see them. For lead and contact forms, honeypot plus server side validation typically catches enough spam without CAPTCHA. Where CAPTCHA is required, hCaptcha and reCAPTCHA v3 (scoring based, no challenge) are more accessible than image grid challenges.


10. Color and Contrast

WCAG 2.2 contrast requirements:

10.1 The 4.5 to 1 Floor

Use WebAIM Contrast Checker or Chrome DevTools color picker. Common failures: light gray body text on white (often 3.5 to 1), light brand color text on white (often below 3 to 1), white text on light backgrounds.

10.2 Large Text Exception

Text at 18 point (24 pixel) and above, or 14 point (18.66 pixel) bold and above, needs only 3 to 1.

10.3 UI Component Contrast

WCAG 2.1 1.4.11 requires UI components (buttons, form input borders, focus indicators, state icons) and graphical objects to hit 3 to 1 against adjacent colors.

10.4 Brand Color Exceptions

Brand color is permissible in non text decorative contexts and prohibited as primary body or CTA text unless contrast passes. CTA solution: pair brand color with dark text overlay or use brand color only as accent.

10.5 Color Never Sole Information Carrier

WCAG 1.4.1 Use of Color. Information conveyed by color must also be conveyed by another means.

<!-- Failure: required marked by red color only -->
<label>Name</label>
<input type="text" name="name" style="border-color: red;">

<!-- Pass: red plus asterisk plus text -->
<label>Name <span aria-hidden="true">*</span><span class="visually-hidden">(required)</span></label>
<input type="text" name="name" required aria-required="true">

10.6 Dark Mode Contrast

:root {
  --color-text: #1a1a1a;
  --color-background: #ffffff;
  --color-link: #0066cc;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-text: #f0f0f0;
    --color-background: #1a1a1a;
    --color-link: #4a9eff;
  }
}

body { color: var(--color-text); background: var(--color-background); }
a { color: var(--color-link); }

10.7 WCAG 3.0 APCA Preview

APCA scores range from -108 to +106 rather than ratio. Approximate targets: 75 for body text, 60 for large text, 45 for UI components. Tooling at apcacontrast.com. Production target stays WCAG 2.2 4.5 to 1 until WCAG 3.0 reaches recommendation.

10.8 Focus Indicator Contrast

The focus indicator must hit 3 to 1 contrast against the unfocused state and background.

:focus-visible {
  outline: 2px solid #0066cc;
  outline-offset: 2px;
}

@media (prefers-color-scheme: dark) {
  :focus-visible { outline-color: #4a9eff; }
}

:focus-visible shows the indicator only on keyboard focus, not on mouse click.


11. Motion and Animation

Motion accessibility addresses three populations: users with vestibular disorders (parallax nausea), users with photosensitive epilepsy (flashing triggers), and users with attention differences (autoplay disruption).

11.1 prefers-reduced-motion

OS setting "Reduce motion" exposes preference via CSS media query.

.hero-animation { animation: slide-in 0.8s ease-out; }
.parallax { transform: translateY(var(--scroll-y)); transition: transform 0.1s linear; }

@media (prefers-reduced-motion: reduce) {
  .hero-animation,
  .parallax {
    animation: none;
    transition: none;
    transform: none;
  }

  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

11.2 Autoplay Video

WCAG 2.2 1.4.2 prohibits autoplay with audio for more than 3 seconds without user control. Operational rule: never autoplay with audio. Muted autoplay is permitted but should pause on prefers-reduced-motion: reduce.

<video autoplay muted loop playsinline aria-label="Decorative background showing workspace">
  <source src="/hero.mp4" type="video/mp4">
</video>
<button id="pause-video" aria-pressed="false">Pause background video</button>
const video = document.querySelector('video[autoplay]');
const button = document.getElementById('pause-video');

if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
  video.pause();
  button.setAttribute('aria-pressed', 'true');
}

button.addEventListener('click', () => {
  if (video.paused) {
    video.play();
    button.setAttribute('aria-pressed', 'false');
  } else {
    video.pause();
    button.setAttribute('aria-pressed', 'true');
  }
});

11.3 Parallax and Large Scale Motion

Enable parallax only when user has not requested reduced motion. Provide settle states that complete quickly when reduced motion is requested.

11.4 Flashing Content

WCAG 2.2 2.3.1 prohibits content flashing more than three times per second. Animated icons, status indicators, and decorative effects must stay below 3 Hz.

11.5 Carousel Auto Advance

Auto advancing carousels must have pause, stop, and hide controls. Prefer non auto advancing carousels or grid layouts. Carousels rank low in engagement research and high in accessibility complexity.


12. Keyboard and Focus Management

Every interactive element must be reachable, operable, and identifiable via keyboard alone.

12.1 Visible Focus Indicator

:focus-visible {
  outline: 2px solid #0066cc;
  outline-offset: 2px;
}

Never use outline: none without a replacement. WCAG 2.2 2.4.7 Focus Visible is critical AA.

12.2 Tab Order

Tab order follows visual reading order. Avoid positive tabindex values (1, 2, 3) which override natural order. Use tabindex="0" to make non focusable element focusable, tabindex="-1" to make element programmatically focusable but not in tab sequence.

12.3 Skip Links

<body>
  <a href="#main-content" class="skip-link">Skip to main content</a>
  <header><nav>...</nav></header>
  <main id="main-content" tabindex="-1">...</main>
</body>

<style>
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px 12px;
  z-index: 100;
  text-decoration: none;
}
.skip-link:focus { top: 0; }
</style>

12.4 Focus Trap in Modals

<button id="open-modal" aria-haspopup="dialog">Open dialog</button>

<div id="dialog" role="dialog" aria-modal="true" aria-labelledby="dialog-title" hidden>
  <h2 id="dialog-title">Dialog title</h2>
  <p>Dialog content.</p>
  <button id="close-modal">Close</button>
</div>
const trigger = document.getElementById('open-modal');
const dialog = document.getElementById('dialog');
const closeBtn = document.getElementById('close-modal');
let previouslyFocused;

function openDialog() {
  previouslyFocused = document.activeElement;
  dialog.hidden = false;
  closeBtn.focus();
  document.addEventListener('keydown', trapFocus);
}

function closeDialog() {
  dialog.hidden = true;
  document.removeEventListener('keydown', trapFocus);
  previouslyFocused.focus();
}

function trapFocus(e) {
  if (e.key === 'Escape') { closeDialog(); return; }
  if (e.key !== 'Tab') return;

  const focusable = dialog.querySelectorAll(
    'a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const first = focusable[0];
  const last = focusable[focusable.length - 1];

  if (e.shiftKey && document.activeElement === first) {
    e.preventDefault();
    last.focus();
  } else if (!e.shiftKey && document.activeElement === last) {
    e.preventDefault();
    first.focus();
  }
}

trigger.addEventListener('click', openDialog);
closeBtn.addEventListener('click', closeDialog);

12.5 Custom Component Patterns

Custom components (comboboxes, listboxes, menus, tabs, accordions) follow ARIA Authoring Practices Guide patterns. If full APG keyboard pattern cannot be implemented, use the native HTML control. A <select> is a fully accessible combobox by default.

12.6 Focus After Route Change in SPAs

function handleRouteChange() {
  const heading = document.querySelector('main h1');
  if (heading) {
    heading.setAttribute('tabindex', '-1');
    heading.focus();
  }
}

Move focus to new page's main heading. Announce via role="status" or aria-live="polite" region.


13. Testing Methodology

Three layers: automated, manual technical, user testing with assistive technology. Each catches issues the others miss.

13.1 Automated Testing

Automated tools catch approximately 30 to 50 percent of WCAG issues. Necessary but not sufficient.

Tool Coverage Integration
axe DevTools Comprehensive WCAG 2.2 ruleset, ~125 rules in free tier Browser extension, CI via axe-core CLI
WAVE Visual indicator overlay, contrast checking Browser extension and web tool
Lighthouse Subset of axe rules Chrome DevTools, Lighthouse CI
Pa11y axe-core or HTML CodeSniffer CLI and CI
Accessibility Insights Microsoft fast pass Browser extension

Automated tools verify: missing alt, unlabeled inputs, contrast, ARIA validity, heading violations, duplicate IDs, empty buttons and links, missing lang attribute, missing title, document structure.

Automated tools cannot verify: whether alt text is meaningful, whether heading text is descriptive, whether keyboard navigation makes logical sense, whether screen reader announcement is useful, whether color is sole information carrier.

13.2 Manual Keyboard Test

keyboard_test_protocol:

  step_1_tab_forward:
    action: "Press Tab from URL bar through end of page"
    verify:
      - "Every interactive element focused in visual order"
      - "Focus indicator visible on every focused element"
      - "Skip link appears as first focusable item"
      - "No unintended focus traps"

  step_2_shift_tab_reverse:
    action: "Shift Tab back through page"
    verify: "Same elements reachable in reverse"

  step_3_activate:
    action: "Tab to each interactive element, Enter or Space"
    verify:
      - "Links navigate on Enter"
      - "Buttons activate on Enter and Space"
      - "Form inputs accept input"

  step_4_modals:
    action: "Open each modal"
    verify:
      - "Focus moves into modal on open"
      - "Tab cycles within modal"
      - "Escape closes modal"
      - "Focus returns to trigger on close"

13.3 Manual Screen Reader Test

Test matrix: VoiceOver on macOS Safari, NVDA on Windows Firefox, JAWS on Windows Chrome (enterprise procurement). For most engagements, VoiceOver plus NVDA covers majority.

screen_reader_test_protocol:

  step_1_overview:
    voiceover: "VO + U to open rotor, navigate landmarks"
    nvda: "Insert + F7 for elements list"
    verify: "Main, navigation, header, footer announced; single H1; logical outline"

  step_2_content:
    action: "Navigate via heading shortcut (H in NVDA, VO+Cmd+H in VoiceOver)"
    verify: "Logical sequence; content addresses headings; no 'click here' anchor text"

  step_3_forms:
    action: "Tab into each form field"
    verify: "Label announced; required state announced; help text via aria-describedby; errors announced on failure"

  step_4_dynamic:
    action: "Trigger form errors, alerts, modal open, route change"
    verify: "Updates announced via aria-live or role=alert; focus management correct"

13.4 Zoom and Reflow Test

WCAG 1.4.10 Reflow requires content at 320 CSS pixel width without two dimensional scrolling. Test by setting browser to 400 percent zoom on 1280 pixel window.

13.5 Forced Colors

Windows High Contrast and macOS Increased Contrast change colors at OS level. CSS forced-colors media query indicates user has enabled it. Use standard CSS keywords: Canvas, CanvasText, LinkText, ButtonText, ButtonFace.

@media (forced-colors: active) {
  .focus-indicator { outline: 2px solid CanvasText; }
  .button-primary {
    background: ButtonFace;
    color: ButtonText;
    border: 1px solid ButtonText;
  }
}

13.6 AT User Testing

When legal exposure matters or enterprise client requires evidence, user testing with people who use assistive technology daily catches what developer testing misses. Typical engagement: 5 to 8 sessions covering screen reader users, keyboard only users, low vision users, cognitive accessibility users.


14. Bubbles Hosted Accessibility Toolchain

Accessibility toolchain runs self hosted on Bubbles Debian server at 169.155.162.118. No third party proxy or external observability. Audit data stays on infrastructure Joseph controls.

14.1 Server Layout

/home/user/a11y/
  node_modules/          # axe-core CLI, Pa11y, Lighthouse CI
  package.json
  scripts/
    audit-site.sh
    audit-page.sh
    weekly-sweep.sh
  config/
    pa11y.json
    lighthouse.json

14.2 axe-core CLI Installation

mkdir -p /home/user/a11y && cd /home/user/a11y

cat > package.json <<'EOF'
{
  "name": "a11y-tools",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "@axe-core/cli": "^4.10.0",
    "pa11y": "^8.0.0",
    "pa11y-ci": "^3.1.0",
    "lighthouse": "^12.0.0",
    "@lhci/cli": "^0.14.0"
  }
}
EOF

npm install

14.3 Pa11y CI Configuration

{
  "defaults": {
    "standard": "WCAG2AA",
    "timeout": 60000,
    "wait": 1000,
    "chromeLaunchConfig": {
      "args": ["--no-sandbox", "--disable-dev-shm-usage"]
    }
  },
  "urls": [
    "https://example.com/",
    "https://example.com/services/",
    "https://example.com/about/",
    "https://example.com/contact/"
  ]
}
/home/user/a11y/node_modules/.bin/pa11y-ci --config /home/user/a11y/config/pa11y.json

14.4 Lighthouse CI Configuration

{
  "ci": {
    "collect": {
      "url": ["https://example.com/", "https://example.com/services/"],
      "numberOfRuns": 3
    },
    "assert": {
      "preset": "lighthouse:recommended",
      "assertions": {
        "categories:accessibility": ["error", { "minScore": 0.95 }]
      }
    },
    "upload": {
      "target": "filesystem",
      "outputDir": "/home/user/a11y/lhci-reports"
    }
  }
}

14.5 Weekly Cron Sweep

crontab -e
# Add:
0 3 * * 1 /home/user/a11y/scripts/weekly-sweep.sh
#!/usr/bin/env bash
# /home/user/a11y/scripts/weekly-sweep.sh

set -e

REPORT_DIR="/home/user/a11y/reports/$(date -u +%Y-%m-%d)"
mkdir -p "${REPORT_DIR}"

SITES=(
  "https://thatdeveloperguy.com"
  "https://thataiguy.org"
  "https://eurekabathworks.com"
  "https://heritagehardwoodfloorsllc.com"
)

for site in "${SITES[@]}"; do
  site_slug=$(echo "${site}" | sed 's|https://||;s|[^a-zA-Z0-9]|_|g')

  /home/user/a11y/node_modules/.bin/axe "${site}" \
    --tags wcag2a,wcag2aa,wcag21a,wcag21aa,wcag22aa \
    --save "${REPORT_DIR}/axe-${site_slug}.json" || true

  /home/user/a11y/node_modules/.bin/pa11y "${site}" \
    --reporter json > "${REPORT_DIR}/pa11y-${site_slug}.json" || true
done

echo "Audit complete. Reports in ${REPORT_DIR}"

14.6 Automated CI on Every Deploy

#!/usr/bin/env bash
# /var/www/sites/[domain]/scripts/a11y-ci.sh

set -e

SITE_URL="${1:-https://example.com}"
REPORT_DIR="/var/www/sites/[domain]/a11y-reports"
TIMESTAMP=$(date -u +"%Y%m%dT%H%M%SZ")

mkdir -p "${REPORT_DIR}"

PAGES=(
  "${SITE_URL}/"
  "${SITE_URL}/services/"
  "${SITE_URL}/about/"
  "${SITE_URL}/contact/"
)

FAIL=0

for url in "${PAGES[@]}"; do
  echo "Auditing: ${url}"
  /home/user/a11y/node_modules/.bin/axe "${url}" \
    --tags wcag2a,wcag2aa,wcag21a,wcag21aa,wcag22aa \
    --save "${REPORT_DIR}/axe-${TIMESTAMP}-$(echo "${url}" | sed 's|[^a-zA-Z0-9]|_|g').json" \
    --exit || FAIL=1
done

if [ "${FAIL}" -eq 1 ]; then
  echo "Accessibility violations found. See reports in ${REPORT_DIR}"
  exit 1
fi

echo "All audited pages pass."

Run on every deploy. Fail deploy on critical or serious violations.

14.7 nginx Configuration

server {
    listen 443 ssl http2;
    server_name example.com;

    location ~* \.(svg|woff2|woff)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    location / {
        add_header Content-Language "en";
        try_files $uri $uri/ =404;
    }

    location = /accessibility/ {
        expires 1h;
        add_header Cache-Control "public, must-revalidate";
    }
}

Framework does not recommend any third party CDN or proxy. nginx on Bubbles serves all client sites directly. Origin is 169.155.162.118. Caching, headers, and TLS terminate on Bubbles. Audit data, server logs, and user behavior signals stay on infrastructure Joseph controls.

14.8 Report Storage

Reports land in /home/user/a11y/reports/[YYYY-MM-DD]/. Directory tree is the audit trail. Client deliverables export to PDF via headless Chrome and share via the Bubbles audit tool in project_audit_tool.md.


15. Audit Mode and Common Failures

15.1 First Pass Audit (Per Page)

For existing site engagement, this five item subset identifies whether the page is fundamentally accessible. Any failure means not WCAG 2.2 AA conformant regardless of other work.

# Criterion Pass/Fail
A1 curl test returns semantic landmarks (main, header, footer, nav) in first byte
A2 Single H1 per page, sequential heading descent
A3 All images have appropriate alt text
A4 All form inputs have associated labels and autocomplete attributes
A5 Color contrast 4.5 to 1 body text, 3 to 1 large text and UI components

15.2 Per Page Audit (Full)

# Criterion Pass/Fail
P1 Lighthouse accessibility score 95+ mobile
P2 axe DevTools zero critical zero serious violations
P3 WAVE zero errors zero contrast errors
P4 Semantic HTML throughout, landmarks present
P5 Heading hierarchy sequential, one H1 per page
P6 All images have appropriate alt text
P7 All interactive elements keyboard accessible with visible focus
P8 Skip link present and operable
P9 Color contrast meets WCAG 2.2 AA
P10 Color not sole information carrier
P11 Forms have proper labels, autocomplete, error association, fieldset
P12 Video has captions, audio has transcript
P13 ARIA used appropriately, semantic HTML preferred where available
P14 prefers-reduced-motion respected
P15 No autoplay with audio
P16 Modal dialogs trap focus and restore on close
P17 Custom components follow ARIA Authoring Practices Guide patterns
P18 Manually tested with NVDA or VoiceOver
P19 Page reflows at 400 percent zoom without horizontal scroll
P20 Forced colors mode usable

Score 20. World class accessibility per page: 18 or higher with zero A1 to A5 fails.

15.3 Site Wide Audit

# Criterion Pass/Fail
S1 WCAG 2.2 AA conformance documented and tested
S2 Accessibility statement published at /accessibility/
S3 Independent audit within last 12 months
S4 Automated CI on every deploy
S5 Manual keyboard and screen reader testing cadence operational
S6 AT user testing completed where legal exposure warrants
S7 Remediation evidence documented
S8 Jurisdiction specific exposure assessed (ADA, EAA, AODA, 508, Unruh)
S9 YMYL pages meet WCAG 2.2 AAA where reasonable
S10 Bubbles hosted toolchain operational, weekly audit reports archived

Score 10. World class accessible site: 9 or higher with zero fails on S1, S2, S4.

15.4 Common Failure Patterns

  1. Treating accessibility as edge case. Roughly 25 percent of US adults live with disability.
  2. Automated tools only. Catches 30 to 50 percent. Manual testing covers the rest.
  3. Placeholder as label. Disappears when typing. WCAG 3.3.2 failure.
  4. Color only differentiation. Pair color with text or icon.
  5. No keyboard testing. Many users cannot use a mouse.
  6. outline: none without replacement. WCAG 2.4.7 failure.
  7. ARIA over semantic HTML. <div role="button" tabindex="0"> instead of <button>. Use semantic HTML first.
  8. Auto captions without correction. Always review and correct.
  9. Inaccessible third party widgets. Replace or document gap in accessibility statement.
  10. Compliance theater. Accessibility statement claiming WCAG 2.2 AA on non conforming site raises rather than lowers exposure.
  11. Missing autocomplete attributes. WCAG 1.3.5 failure. Reduces form completion via disabled autofill.
  12. Heading skip. H1 to H3 directly fails screen reader navigation. Common in CMS templates.
  13. Decorative images with alt text. Adds noise. Empty alt="" is correct.
  14. Informational images with empty alt. Removes information from screen reader users. WCAG 1.1.1.
  15. Modal that does not trap focus. Tab leaves modal, reaches background content.

15.5 Remediation Priority Order

  1. Critical (axe critical, screen reader broken, keyboard inaccessible primary flows)
  2. Serious (contrast failures on primary text, missing form labels, missing alt on informational images)
  3. Moderate (heading hierarchy, ARIA misuse not blocking access)
  4. Minor (decorative image with non empty alt, redundant ARIA)
  5. AAA aspirational (enhanced contrast, sign language, no time limits)

16. Maintenance Schedule and Report Templates

16.1 Maintenance Cadence

Daily. CI on every deploy runs axe-core and Pa11y. Failed deploys block merge. Weekly. Bubbles cron sweep across priority pages. Manual keyboard test on new features. Monthly. Manual screen reader test on changed pages. Review audit trends. Update accessibility statement if conformance changed. Quarterly. Full Section 15 audit. Refresh accessibility statement. Brief stakeholder on findings. Annually. Independent third party audit. Refresh against current WCAG version. Strategic review of legal exposure.

16.2 Audit Report Template

# Accessibility Framework Audit Report

**Site**: {{BUSINESS_NAME}}
**Audit Date**: {{TODAY}}
**WCAG Version Targeted**: 2.2 AA
**Jurisdiction**: {{JURISDICTION}}

## Executive Summary

One paragraph assessment of conformance posture, top three risks, recommended remediation order.

**Site wide score**: X/10
**Average priority page score**: X/20
**Critical violations**: X
**Serious violations**: X
**Legal exposure assessment**: NONE | LOW | MODERATE | HIGH

## Findings by Section

Section 6 Semantic HTML, Section 7 Heading Hierarchy, Section 8 Image Accessibility, Section 9 Form Accessibility, Section 10 Color and Contrast, Section 11 Motion and Animation, Section 12 Keyboard and Focus.

## Critical Failures

List with location, WCAG criterion, severity, remediation path.

## First Pass Subset Findings

Per priority page table of A1 to A5 results.

## Recommended Remediation Order

1. Critical
2. Serious
3. Moderate
4. Minor

## Sign-Off

16.3 Implementation Report Template

# Accessibility Framework Implementation Report

**Site**: {{BUSINESS_NAME}}
**Implementation Date**: {{TODAY}}
**WCAG Target**: 2.2 AA

## Summary

- Pages remediated: X of Y
- Critical violations remediated: X of Y
- Serious violations remediated: X of Y
- Accessibility statement published: Yes/No
- Automated CI operational: Yes/No
- Weekly manual cadence operational: Yes/No

## Substrate Work

Semantic markup pass count, heading hierarchy corrections, form label additions, autocomplete additions, alt text rewrites.

## Color and Motion Work

Contrast remediations, prefers-reduced-motion handling, autoplay video remediation.

## Testing Infrastructure

axe-core CLI installed on Bubbles, Pa11y CI configured, Lighthouse CI configured, weekly cron sweep operational.

## Sign-Off

End of Framework Document

Document version: 2.0 Created: 2026-05-14 Maintained by: ThatDeveloperGuy

Accessibility in 2026 is structural quality. The same semantic markup screen readers consume is what AI engines parse for citation. The same heading hierarchy supporting screen reader navigation supports AI Overview answer extraction. The same form labels making a field operable by assistive technology raise the form completion rate. The disciplines reinforce each other so completely that treating accessibility as separate from SEO and AEO is operational waste.

Apply in parallel with framework-uxseo.md, framework-pageexperience.md, framework-mobileseo.md, framework-imageseo.md, framework-videoseo.md, framework-formoptimization.md, framework-schema.md, framework-technicalseo.md, framework-eeat.md, and framework-aicitations.md. For React and Tailwind specific guidance see framework-react.md and framework-tailwind.md.

Companions

Want this framework implemented on your site?

ThatDevPro ships these frameworks as productized services. SDVOSB-certified veteran owned. Cassville, Missouri.

See Engine Optimization service ›