Accessibility Playbook
On this page
The floor: WCAG 2.1 AA + Section 508
Both — the Web Content Accessibility Guidelines (WCAG) 2.1 at level AA, and Section 508 of the Rehabilitation Act — are non-negotiable for government deployment. Every surface CRAIG ships — core panels, jurisdiction plugins, public-facing portals, print outputs — adheres to both standards or does not ship.
Validated against:
-
The NVDA, JAWS, and VoiceOver screen readers
-
Keyboard-complete operation (no pointer required for any action)
-
Reduced-motion preference honored everywhere
Focus is always visible
Focus indication is never removed for aesthetics. The rule is mechanical:
-
:focus-visible→ 3 px gold ring (Statehouse) / 3 px terracotta ring (Foundation), 2 px offset -
Focus order follows visual order. Tab moves through focusable elements in the order they read on the page.
-
Modals trap focus + return it to the trigger on close.
-
No
outline: none— CSS reset that strips focus is rejected at PR review.
The 3 px ring color uses --accent (decoration token) — never carries text contrast (see Brand Identity, Palettes, and Typography).
As built, the branded ring is still rolling out: the shipped custom :focus-visible rule covers the case-detail tab strip (2 px --link, in components.css), and every other surface keeps the browser’s default focus ring — nothing strips it, so focus is visible everywhere. The 3 px --accent ring above is the contract new CSS adopts.
Color is never the only signal
Icon + label always accompany hue. Status conveyed three ways:
| Status | Hue | Icon | Label |
|---|---|---|---|
Substantiated |
red |
⚠ |
"Substantiated" |
Safe |
green |
✓ |
"Safe" |
Due soon |
amber |
◷ |
"Due soon" |
Overdue |
red |
✕ |
"Overdue" |
In progress |
blue |
◐ |
"In progress" |
Pending |
gray |
◯ |
"Pending" |
Why: red/amber/green read identically to many color-blind users and disappear in high-contrast mode. The icon and word carry the meaning; color is reinforcement.
Red is reserved for danger — never branding, never decoration. See Brand Identity, Palettes, and Typography § red is reserved exclusively for danger.
The keyboard model
Every action is reachable without a pointer. Tab order equals visual order, everywhere.
| Key | Action |
|---|---|
|
Open the command palette from anywhere |
|
Close palette, modal, drawer, or popover — focus returns to the trigger |
|
Move through focusable elements in visual order |
|
Move between tabs (case workspace, settings) — per the WAI-ARIA (Accessible Rich Internet Applications) tabs pattern |
|
First / last tab in a tablist |
|
Move & select within the palette, worklists, and menus |
|
Reorder a panel or case section in the composable grid — drag-free |
|
Open the keyboard-shortcut help sheet |
This table is the contract each surface adopts as it ships. Built today: Tab/Shift+Tab traversal, Esc on the native <dialog> modals, and Enter activation on the case-detail tab strip (the mechanism the VPAT records). The command palette, arrow-key/Home/End tablist navigation, panel reorder, and the shortcut help sheet ship with their surfaces.
Composability is keyboard-complete, by contract. When panel and case-section rearrangement ships, the drag interaction must have a full keyboard equivalent (Alt+↑/↓), announced via an ARIA live region ("Moved Placement above Court"). Neither reorder path exists yet — both composition surfaces (Studio and Personalize) currently render placeholder text where the reorder controls will live.
Semantic landmarks + ARIA
Screen-reader users navigate by landmark. Every chrome region is labeled.
Landmark map (worker screen reference)
| Landmark | What it labels |
|---|---|
skip-link |
First focusable element on the page → jumps to |
|
App chrome · brand · ⌘K search · user |
|
Breadcrumb · |
|
The case workspace / dashboard / focal surface |
|
The persistent case spine |
|
Footer · powered-by |
The shipped chrome carries the first four rows (skip-link, banner, breadcrumb navigation, main — all in the shared base template); the complementary and contentinfo rows apply when the case spine and footer regions ship.
Component-level commitments
-
Tabs:
role=tablist·aria-selected· arrow-key nav -
Form errors: linked to inputs via
aria-describedby— field-attached, on blur, never color-alone -
Modals: focus trap + return;
role=dialog·aria-modal -
Tables: semantic
<table>· sortable headers announce sort state -
Alerts:
role=alertfor danger; live regions for async updates -
SR-only context via
.sr-onlywhere visual shorthand needs spelling out
Contrast, motion, modes
Contrast
-
Body text ≥ 4.5:1
-
Large text + UI elements ≥ 3:1
-
Audited per release, both light AND dark
-
High-contrast mode ships alongside light/dark (required for state systems that demand it)
-
--accent(gold / peach / terracotta) is decoration only — it never carries text contrast
Motion
-
prefers-reduced-motiondisables the skeleton pulse + caret blink -
Entrance animations fall back to end-state when reduced-motion is set
-
No parallax. No background video. No autoplay anything.
Reading level
-
Constituent copy targets Grade 6. The built public reporting portal targets sixth-grade reading level, as will the Phase 11 family and foster portals when they are built. The Hemingway-app score is checked at PR review.
-
Caseworker copy uses glossary tooltips for unavoidable terms: statutory language, Adoption and Foster Care Analysis and Reporting System (AFCARS) field names, and Interstate Compact on the Placement of Children (ICPC) categories.
-
Labels carry through i18n — Spanish ~+20% length is accommodated, RTL not prevented.
Print + legal output
Print output (court reports, AFCARS submission previews, National Child Abuse and Neglect Data System — NCANDS — submission previews) is designed as a distinct surface. No print stylesheet ships yet; these are the requirements each print surface meets as it lands:
-
All structural elements use semantic HTML; the screen + print stylesheets share semantics + diverge on layout only.
-
Page breaks are deterministic: section heads do not orphan; tables that span pages repeat the column header on each page.
-
Hyperlinks expand to footnoted URLs in print mode (since clicking is not available).
-
Print is monochrome-safe — anything that relied on color for meaning is replicated as label + icon in print mode.
Where these rules land in code
-
Focus indication: the contract target is one canonical shared
:focus-visiblerule; today the shipped custom rule lives inservices/craig-web/static/css/components.css(tab strip) and other surfaces keep the browser default ring (see § Focus is always visible). -
Keyboard model: implemented at the backend-for-frontend (BFF, craig-web) route + template layer + per-plugin (Contract 1) author responsibility.
-
Semantic landmarks: carried by the shared base template today; extending the F-021 template-safety lint (
cargo xtask validate-template-safety) to verify landmark presence is planned, not yet built. -
prefers-reduced-motion: every CSS animation MUST carry a@media (prefers-reduced-motion: reduce)override. Shipped CSS currently has no keyframe animations (only two brief transitions), and the enforcing build-time lint is planned. -
Contrast: the shipped machine guard is the #643 test that
--accentnever carries text contrast (services/craig-web/src/theme.rs); the systematic per-pair WCAG-ratio scanner lands with #641. New tokens must declare both light + dark mode + pass contrast for body + UI use cases. -
Print stylesheet: per-page-template + per-plugin author responsibility; PR review verifies.
Source + provenance
-
External design team, settled 2026-06-08
-
Master narrative:
docs/handoffs/2026-06-08-design-response/mockups/CRAIG Accessibility Playbook (Statehouse).html(interactive demo of focus ring, keyboard shortcuts, landmark map) -
Engagement-archive bundle:
docs/handoffs/2026-06-08-design-response/ -
Related: The Four-State Panel Contract (every panel state must remain accessible), Brand Identity, Palettes, and Typography (red is reserved for danger; high-contrast mode required), The Five Engineering Contracts (Contract 1 plugin manifest enforces
states_required) -
Compliance reference: VPAT 2.5 — Section 508 / WCAG 2.1 AA (the formal vendor accessibility template CRAIG publishes)