Delta-V uses a Canvas game board. Full non-visual play would require a parallel interface and is not currently in scope. This guide focuses on the accessible parts of the product we do control: menu, lobby, overlays, HUD chrome, fleet builder, chat, and buttons.
In scope:
src/client/ui/src/client/dom.ts- Overlay and lobby controls rendered outside Canvas
Out of scope (for now):
- Pointer-first ship/hex interaction on the Canvas board
- Full keyboard-only tactical play parity
Run this checklist:
- Before release candidates
- After major UI refactors
- After introducing new modal, form, or HUD interaction patterns
Run both automated paths when possible:
- Lighthouse Accessibility audit on
/ - Playwright + axe baseline:
npm run test:e2e:a11y- Covers menu, waiting lobby, HUD + help overlay DOM
- Fails on serious/critical violations
- Excludes Canvas and
color-contrast(tracked manually in checklist)
Pass criteria:
- No critical/serious accessibility violations on audited views
- New violations are either fixed or explicitly documented (e.g.
docs/BACKLOG.mdwhen scoping follow-up)
- Keyboard order: Tab order reaches Create/Join and primary actions in expected sequence
- Activation semantics: Enter/Space activate controls; native
<button>preferred over clickable<div> - Form naming: room code/chat inputs have visible labels or correct
aria-label - Focus visibility: keyboard focus ring/outline is visible on all actionable elements
- Modal behavior: focus is trapped while open and restored to trigger on close
- Contrast: HUD/overlay text is readable on translucent backgrounds — follow MANUAL_TEST_PLAN.md § Contrast & readability for WCAG AA spot-check steps on glassy panels (help overlay, game-over)
- Status messaging: important toasts/errors use
role="status"orrole="alert"where signal is needed without excessive noise
Document Canvas constraints explicitly in PRs/issues when relevant. Do not create placeholder "keyboard support" tasks without a concrete product decision and implementation plan.
The tactical map stays role="application" with a long aria-label so assistive tech exposes it as a single complex control rather than browse-mode noise. Full non-visual play on the hex grid is still out of scope (see Scope above).
To partially offset browse-mode loss, #hudBoardSummary (visually hidden, role="status", aria-live="polite") is updated from HUD chrome with high-level board context (turn, phase, objective text). That documents the current product choice: keep application on the canvas and push lightweight state narration to a dedicated live region instead of switching the canvas to role="img".
When running an audit, add a short note to the PR or backlog using this template:
- Date:
- Surfaces checked:
- Automated results:
- Manual checklist summary:
- New issues found:
- Follow-up tickets/backlog links:
- Date: 2026-04-24
- Surfaces checked: automated
test:e2e:a11y(8/8 pass), menu + in-game HUD + help overlay + game-over + reconnect overlay at 375 × 812,:focus-visibleCSS inventory,prefers-reduced-motion/prefers-contrastcoverage, live-region inventory, HUD-scale discoverability. - Automated results:
npm run test:e2e:a11ypasses — 8/8 axe checks on menu, menu contrast, waiting lobby, in-game HUD + help, keyboard activation of primary nav, help-overlay focus move and restore, fleet-building screen, desktop log panel. - Manual checklist summary:
- Keyboard order: primary flows pass; help, game-over, and reconnect overlays implement Tab focus traps (hud-chrome-view.ts:540-566, overlay-view.ts).
- Activation semantics: native buttons and radios with
roleattributes; Enter/Space work. - Form naming: callsign / room-code / chat inputs have
aria-labelor visible labels. - Focus visibility: global
:focus-visiblering applied at 2px solid accent with 2px offset (base.css:215-223). - Modal behavior:
#helpOverlay,#gameOver, and#reconnectOverlayhave botharia-modal="true"and Tab focus traps. - Contrast:
prefers-contrast: moredrops backdrops on HUD / overlays / phase alert / menu (good); translucent HUD text still needs per-device spot-check on real hardware. - Status messaging: 14
aria-liveregions in static/index.html (hudBoardSummary, callsignStatus, gameCode, toastContainer, phaseAlert, logEntries, logLatestBar, opponentDisconnectOverlay, newVersionBanner, menuOfflineBanner, officialBotOffer, chatCharCounter, logStatusBar, logistics container). Comprehensive.
- New issues found:
prefers-reduced-motiondisables only 5 selectors; 12@keyframes+ 32 animation/transition rules otherwise fire. Canvas animation layer ignores the setting entirely (nomatchMedia('(prefers-reduced-motion: reduce)')in src/client/).- HUD scale is keyboard-only (
+/_) with no touch-reachable UI and no visible discoverability — touch users who most need larger text can't adjust it.
- Follow-up: filed as a single Low-Friction Accessibility Polish (P2) entry in BACKLOG.md. Full keyboard tactical play on the canvas board remains explicitly out of scope.
- Date: 2026-04-18
- Surfaces checked: same as 2026-04-03 pass, plus HUD text-size controls, help TOC links, quick-match waiting elapsed copy, chat character counter,
#hudBoardSummaryupdates during play - Automated results:
npm run test:e2e:a11ypassed on this date after the UI batch (seee2e/a11y.spec.tsfor the current suite) - Manual checklist summary:
- Keyboard order: unchanged pass for menu primary actions and help overlay open/close flow
- Activation semantics: unchanged pass on audited controls; native buttons remain the default
- Form naming: unchanged pass for room-code and chat inputs
- Focus visibility: global
:focus-visiblering added in CSS; still verify per-browser during release passes - Modal behavior: unchanged pass for help/reconnect/game-over dialog semantics
- Contrast: global and
prefers-contrast: moretweaks landed; translucent HUD surfaces still need human visual check - Status messaging:
#hudBoardSummaryadds polite board-context narration; other live regions unchanged
- New issues found: none serious/critical in axe baseline; remaining gaps include full keyboard map parity and auditing duplicate copy across HUD status / game log / toasts (
preferNotificationChannelis available at call sites) - Follow-up: track in BACKLOG.md or issues when scoping
- Date: 2026-04-03
- Surfaces checked: all
src/client/ui/*.tsview files,static/index.html,src/client/dom.ts - Method: grep-based scan for clickable non-interactive elements missing
role,tabIndex,aria-label, or keyboard handlers - Findings and fixes:
- Fleet cart chips (
fleet-building-view.ts): clickabledivelements lackedrole="button",tabIndex,aria-label, and keyboard activation. Fixed. - Ship list entries (
ship-list-view.ts): hadrole="button"andaria-labelbut were missingtabIndexand Enter/Space keyboard handler. Fixed. - Log latest bar (
game-log-view.ts): clickabledivused to expand the game log lackedrole="button",tabIndex, and keyboard handler. Fixed.
- Fleet cart chips (
- No missing
alttext on images, no missingaria-labelon icon buttons, no form inputs without labels found. tsc --noEmitpasses; full Vitest suite passes.
Track concrete fixes in BACKLOG.md when you file scoped work. Prefer specific, testable items over broad "improve accessibility" entries.