Plan: Section 508 / WCAG 2.1 AA Accessibility Compliance

On this page

Status

Step Description Status

1

Plan file and nav entry

Done (pre-ADR-030)

2

Accessibility audit (automated + manual)

Done (pre-ADR-030) — 41 pages audited, axe-core infrastructure in place

3

Remediation — semantic HTML + ARIA

Done (pre-ADR-030) — case detail tab-strip: role="tablist"/role="tab", aria-selected, keyboard enter

4

Remediation — keyboard navigation

Done (pre-ADR-030) — tab-strip keyboard navigation with tabindex + @keydown.enter

5

Remediation — color contrast + visual

Done (2026-03-21) — MR !51 — all pages WCAG AA clean

6

Remediation — form accessibility

N/A — forms passed audit (proper labels, required attributes)

7

Remediation — table accessibility

N/A — tables passed audit

8

Axe-core CI integration

Done (pre-ADR-030) — audit spec converted to blocking gate; 41 pages clean; ACCESSIBILITY_AUDIT env-var gate removed from [playwright.config.ts](tests/e2e/playwright.config.ts) and [xtask/src/cmd/e2e.rs](xtask/src/cmd/e2e.rs)

9

Verification + VPAT document

Done (pre-ADR-030) — [vpat.adoc](docs/modules/ROOT/pages/vpat.adoc) published under Operations nav

10

Documentation, commit, push, MR

Done (pre-ADR-030) — this MR

Issues: TBD (audit + remediation work landed via MR !51; file a tracking issue when picking up the residual steps 8–10)
Branch: feature/accessibility-508

Steps 1–7 (audit + remediation) are shipped. This plan’s residual scope is axe-core CI integration (step 8), VPAT document (step 9), and plan-completion MR (step 10). The Design sections below for steps 3–7 are retained as historical context; they describe work already on main.

Context

Section 508 compliance is a federal legal requirement for systems that process Title IV-E data. CRAIG’s web UI (craig-web) was built with htmx + Alpine.js + Askama templates. Some accessibility basics are in place (semantic HTML, form labels), but no systematic audit has been performed and no VPAT (Voluntary Product Accessibility Template) exists.

The roadmap marks accessibility as "partial" (roadmap.adoc:298).

Scope

In scope:

  • Automated accessibility audit of all 25+ web pages using axe-core

  • Manual keyboard navigation audit

  • Remediation of all WCAG 2.1 Level AA violations

  • Axe-core integration in E2E test suite (Playwright + @axe-core/playwright)

  • Partial VPAT document

Out of scope:

  • WCAG 2.1 Level AAA (aspirational, not required by Section 508)

  • Screen reader testing with specific assistive technologies (would require manual QA)

  • PDF accessibility (document exports)

Design

Step 2 (audit) must be completed before Steps 3-7 can be fully specified. The remediation steps below list expected categories of issues based on common web application patterns. Exact issues will be documented after the audit.

Step 2: Accessibility Audit

Run axe-core against all pages via Playwright:

import AxeBuilder from '@axe-core/playwright';

test('page has no accessibility violations', async ({ page }) => {
  await page.goto('/cases/');
  const results = await new AxeBuilder({ page })
    .withTags(['wcag2a', 'wcag2aa', 'section508'])
    .analyze();
  expect(results.violations).toEqual([]);
});

Run against all 25+ pages. Document each violation with: * Rule ID (e.g., color-contrast, label, aria-required-attr) * Affected element(s) * Impact level (critical, serious, moderate, minor) * Template file and line number

Expected Remediation Categories

Step 3: Semantic HTML + ARIA

Common issues: * Missing role attributes on interactive elements * Missing aria-label on icon-only buttons * Missing aria-live regions for htmx dynamic content updates * Landmark roles (main, nav, banner, contentinfo) on layout elements

Files: templates/base.html (layout landmarks), all templates with buttons/links

Step 4: Keyboard Navigation

Common issues: * Focus trapping in Alpine.js modals/dropdowns * Tab order for sortable table headers * Skip-to-content link * Focus visible indicators (:focus-visible CSS)

Files: static/css/components.css, templates with Alpine.js x-show/x-data

Step 5: Color Contrast + Visual

Common issues: * Badge text contrast ratios below 4.5:1 * Muted text (color-sage) contrast ratio * Focus indicator contrast * Error state visibility (not color-alone)

Files: services/craig-web/static/css/tokens.css, services/craig-web/static/css/components.css (actual CSS layout — no theme-georgia-orchard.css file exists; theme is composed via token layers)

Step 6: Form Accessibility

Common issues: * <label> elements properly associated with inputs via for/id * Required field indicators (not color-alone) * Error message association via aria-describedby * Form validation announcements

Files: All new_*.html and form templates

Step 7: Table Accessibility

Common issues: * <th scope="col"> on all table headers * <caption> or aria-label on data tables * Row/column relationships for complex tables

Files: All list templates with data-table class

Step 8: Axe-core CI Integration

The audit spec tests/e2e/specs/accessibility-audit.spec.ts already exists with axe-core infrastructure. Step 8 upgrades it to a blocking CI gate: wire the existing spec into the default test matrix (currently it’s invoked manually during audits) and fail the pre-push battery on any AA violation. Also add @axe-core/playwright to the Playwright project matrix in tests/e2e/playwright.config.ts.

// tests/e2e/package.json — add dev dependency
"@axe-core/playwright": "^4"

Verification

  1. Axe-core reports zero violations on all pages (AA level)

  2. All pages keyboard-navigable without mouse

  3. Color contrast ratios meet 4.5:1 for normal text, 3:1 for large text

  4. All form inputs have associated labels

  5. All data tables have proper header scope

  6. Existing E2E tests pass unchanged

Documentation Updates

  • CHANGELOG.adoc

  • docs/modules/ROOT/pages/roadmap.adoc — update from "partial" to complete

  • Create VPAT document (accessibility conformance report)

Edit this page · latest