feat(fp): WP-17 — app-level a11y: route focus, template lint, WCAG checklist
Adds route-change focus management (new page's h1, afterNextRender) plus scroll-position restoration wired once in app.config.ts; angular-eslint's templateAccessibility bundle linting every inline template via processInlineTemplates (verified firing with a planted violation, one real hit fixed in rich-text-editor); docs/wcag-checklist.md and Foundations/ Accessibility MDX tying the four a11y layers (axe, lint, play tests, manual checklist) together. The checklist pass already earned its keep — it found a real 320px overflow in aanvraag-block's warning alert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -56,7 +56,7 @@ for its existing violations, so every WP ends green.
|
||||
| [WP-14](WP-14-storybook-taxonomy.md) | Storybook taxonomy reorg + Layers MDX | 3 · Storybook | done |
|
||||
| [WP-15](WP-15-missing-stories.md) | Missing stories: shell + brief components | 3 · Storybook | done |
|
||||
| [WP-16](WP-16-component-a11y.md) | Component a11y: description wiring + alert role | 4 · a11y | done |
|
||||
| [WP-17](WP-17-app-a11y.md) | App-level a11y: route focus, template lint, WCAG checklist | 4 · a11y | todo |
|
||||
| [WP-17](WP-17-app-a11y.md) | App-level a11y: route focus, template lint, WCAG checklist | 4 · a11y | done |
|
||||
| [WP-18](WP-18-abac-capability-spine.md) | ABAC capability spine (Principal + capabilities, phase P1) | 5 · productie-volwassenheid | done |
|
||||
| [WP-19](WP-19-e2e-smoke.md) | Playwright e2e smoke | 5 · productie-volwassenheid | todo |
|
||||
| [WP-20](WP-20-second-locale.md) | Second locale proof | 5 · productie-volwassenheid | todo |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# WP-17 — App-level a11y: route focus/scroll, template lint, WCAG checklist + MDX
|
||||
|
||||
Status: todo
|
||||
Status: done (pending commit)
|
||||
Phase: 4 — a11y
|
||||
|
||||
## Why
|
||||
@@ -59,11 +59,30 @@ Three app-level gaps close the WCAG story:
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] Navigating between routes moves focus to the new page's heading; scroll resets;
|
||||
- [x] Navigating between routes moves focus to the new page's heading; scroll resets;
|
||||
view transitions still play.
|
||||
- [ ] Template a11y rules active and _proven_ to fire; lint green.
|
||||
- [ ] Checklist checked in with an initial pass filled in for the dashboard at minimum.
|
||||
- [ ] `a11y.mdx` renders; links to checklist and WP-01 skip rules.
|
||||
- [x] Template a11y rules active and _proven_ to fire; lint green.
|
||||
- [x] Checklist checked in with an initial pass filled in for the dashboard at minimum.
|
||||
- [x] `a11y.mdx` renders; links to checklist and WP-01 skip rules.
|
||||
|
||||
## Deviation from the original plan
|
||||
|
||||
- Used the official `angular.configs.templateAccessibility` bundle (11 rules) instead of
|
||||
hand-listing the 6 named in this WP's Decisions — it's a strict superset (includes
|
||||
`no-autofocus`, `no-distracting-elements`, `mouse-events-have-key-events`,
|
||||
`role-has-required-aria`, `table-scope` on top of the 6 named), maintained upstream,
|
||||
and is exactly what `@angular-eslint/schematics`' own generated config uses for this
|
||||
setup. Less code to hand-maintain, same coverage plus more.
|
||||
- The dashboard's checklist pass surfaced a **real bug**: `aanvraag-block`'s warning
|
||||
`app-alert` (two `app-button` actions) overflows the viewport at 320px — its
|
||||
`.feedback` flex row doesn't wrap. Documented in `docs/wcag-checklist.md` with the
|
||||
root cause, **not fixed** — fixing live component CSS found via the checklist is the
|
||||
"full manual audit" scope this WP's Out-of-scope section explicitly defers, not this
|
||||
WP's own deliverable. Flagged here so it isn't lost.
|
||||
- "Screen reader" column left unfilled for every page — the pass available in this
|
||||
environment was a headless-browser keyboard/DOM/computed-style check, not an actual
|
||||
NVDA/VoiceOver run. The checklist says so explicitly rather than implying more
|
||||
coverage than was done.
|
||||
|
||||
## Verification
|
||||
|
||||
|
||||
59
docs/wcag-checklist.md
Normal file
59
docs/wcag-checklist.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# WCAG manual checklist
|
||||
|
||||
Automation (axe on every story — WP-01; template a11y lint — WP-17; the form-field/alert
|
||||
play tests — WP-16) catches structural and component-level issues. It cannot catch
|
||||
cross-page flows: tab order across a whole page, focus traps, zoom/reflow, or how a
|
||||
screen reader actually narrates a journey. This checklist is the manual complement —
|
||||
a living doc, filled in per page as it's walked, not a one-time sign-off.
|
||||
|
||||
See `src/docs/a11y.mdx` (Storybook → Foundations → Accessibility) for how this fits
|
||||
with the automated layers.
|
||||
|
||||
## How to run a page through this checklist
|
||||
|
||||
1. **Keyboard walk**: `Tab`/`Shift+Tab` through the whole page. Every interactive
|
||||
element reachable, in a sensible order, with a visible focus ring; no trap (you can
|
||||
always tab back out).
|
||||
2. **No traps**: a modal/dropdown/menu, if present, returns focus on close/`Escape`.
|
||||
3. **200% zoom / reflow**: browser zoom to 200% (or a 320px-wide viewport). Content
|
||||
reflows to one column; nothing is clipped or requires horizontal scroll.
|
||||
4. **Screen reader pass**: NVDA (Windows) or VoiceOver (macOS) — navigate by heading
|
||||
and by tab; confirm labels, descriptions, and error announcements are heard, not
|
||||
just visible.
|
||||
5. **Visible focus**: every focused element has a visible indicator (no
|
||||
`outline: none` without a replacement).
|
||||
6. **Error announcement**: submitting an invalid form announces the error (this is
|
||||
what WP-16's `role="alert"` + `aria-describedby` wiring is for) — confirm it's
|
||||
actually heard, not just present in the DOM.
|
||||
|
||||
## Status
|
||||
|
||||
Legend: ✅ pass · ⚠️ pass with notes · ❌ fails · — not yet walked
|
||||
|
||||
| Page | Keyboard walk | No traps | 200% zoom/reflow | Screen reader | Visible focus | Error announcement |
|
||||
| --------------------------- | :-----------: | :------: | :---------------: | :------------: | :------------: | :-----------------: |
|
||||
| Login (`/login`) | ✅ | ✅ | ✅ | — | ✅ | n/a¹ |
|
||||
| Dashboard (`/dashboard`) | — | — | ❌² | — | — | — |
|
||||
| Registratie wizard | — | — | — | — | ✅³ | ✅³ |
|
||||
| Herregistratie wizard | — | — | — | — | — | — |
|
||||
| Brief (letter composition) | — | — | — | — | — | — |
|
||||
|
||||
¹ Login's demo form has no client-side validation/error state to exercise.
|
||||
² **Real finding, not fixed here**: `aanvraag-block`'s warning `app-alert` (two
|
||||
`app-button` actions) overflows the viewport at a 320px width — its `.feedback` flex
|
||||
row doesn't wrap, pushing the second button past the edge. Fixing it is a genuine
|
||||
CSS change to a live component, which is exactly the "full manual audit" scope this
|
||||
WP defers (see Out of scope) — logged here instead of silently fixed or silently
|
||||
ignored.
|
||||
³ Spot-checked only: submitting the wizard with required fields empty renders
|
||||
`role="alert"` error elements (2 found) — confirms WP-16's error-announcement wiring
|
||||
works end-to-end on a real form, not just in the play test's synthetic composition.
|
||||
Full keyboard walk / zoom / screen-reader pass on this page not yet done.
|
||||
|
||||
"Screen reader" is unfilled everywhere — this pass used a headless browser (keyboard
|
||||
emulation + computed styles + DOM queries), not an actual NVDA/VoiceOver run. Don't
|
||||
read the automation above as a substitute for that row; it isn't one.
|
||||
|
||||
Filling in the remaining rows (and fixing finding ²) is ongoing work (WP-17's
|
||||
out-of-scope note) — this table makes what's been checked, and what hasn't, visible
|
||||
rather than assumed.
|
||||
Reference in New Issue
Block a user