All checks were successful
CD / Build and push images (push) Successful in 1m12s
CD / Deploy to Test (push) Successful in 11s
CD / Smoke tests against Test (push) Successful in 1m13s
CD / Promote to Int (push) Successful in 11s
CI / Lint, typecheck, test (push) Successful in 4m45s
CI / Build container images (push) Has been skipped
CI / Auth e2e pack (push) Successful in 7m15s
CI / Import/export fidelity gate (push) Successful in 56s
Release / Build release images and notes (push) Successful in 1m11s
Release / Release-candidate operations QA (push) Successful in 44s
Prod deploy / Deploy the released images to Prod (push) Successful in 16s
Jede künftige UI-Änderung entwickelt Barrierefreiheit direkt mit (Stefans Vorgabe nach Abschluss des WCAG-2.1-AA-Audits): verbindliche Checkliste als ADR, Kurzfassung in CLAUDE.md für jede Dev-Session, Eintrag im ADR-Index. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AGM8jo3hwoV9wsCVGfy8iq
73 lines
3.6 KiB
Markdown
73 lines
3.6 KiB
Markdown
# ADR 0017: Accessibility (WCAG 2.1 AA) as a default requirement
|
||
|
||
- Status: accepted
|
||
- Date: 2026-07-21
|
||
|
||
## Context
|
||
|
||
A full WCAG 2.1 AA audit (July 2026) found a solid baseline — enforced
|
||
accessible names on `IconButton`, the implicitly labelling `Field`
|
||
primitive, localized ARIA labels, a clean landmark structure — but also
|
||
systemic gaps that had accumulated because accessibility was checked
|
||
after the fact rather than built in: dialogs without focus management, a
|
||
hard-coded document language, broken listbox semantics, page-level
|
||
horizontal scrolling at 320 px viewport width. All findings were fixed in
|
||
issues #162–#171; an axe-core smoke pack (`apps/web/e2e/a11y.spec.ts`)
|
||
now pins the core screens in CI.
|
||
|
||
Retro-fitting accessibility is far more expensive than building it in.
|
||
This ADR makes it a default requirement for every future feature.
|
||
|
||
## Decision
|
||
|
||
**Every user-facing change ships accessible.** Concretely, a feature is
|
||
not done until it satisfies this checklist:
|
||
|
||
1. **Reuse the accessible primitives.** Icon-only controls go through
|
||
`IconButton` (enforces a name); form controls go through `Field`
|
||
(label + `aria-describedby`/`aria-invalid` wiring); dialogs use
|
||
`useModalFocus` (focus trap, initial focus, focus return) plus
|
||
`aria-labelledby` on their heading. Do not hand-roll parallels.
|
||
2. **Keyboard first.** Everything reachable and operable by keyboard,
|
||
visible focus, Escape closes overlays, no focus loss on unmount. New
|
||
single-key shortcuts must respect the "disable single-key shortcuts"
|
||
setting (`lib/single-key-shortcuts.ts`).
|
||
3. **Name, role, value.** New widgets carry correct roles and
|
||
localized (de+en) accessible names; state via `aria-expanded`,
|
||
`aria-selected`, `aria-pressed` etc. Decorative icons stay
|
||
`aria-hidden`.
|
||
4. **Both render paths.** Anything that renders content must behave
|
||
identically in the editor/NodeView path AND the `docToHtml`/server
|
||
path (public view, comments, previews) — including labels and list
|
||
semantics. Remember: `page_content_cache` rolls out `docToHtml`
|
||
changes lazily (on next persist).
|
||
5. **Color and contrast.** Use the design tokens; text ≥ 4.5:1, UI
|
||
boundaries and icons ≥ 3:1 (`--color-border-input` exists for field
|
||
borders; `--color-favorite` is icon-only). Color is never the only
|
||
cue. Dark-rendered surfaces (public shell) keep their checked colors.
|
||
6. **Reflow.** New layouts must not force page-level horizontal
|
||
scrolling at 320 px (flex/grid children need `min-width: 0`;
|
||
intrinsically wide content scrolls in its own focusable container).
|
||
7. **Motion and time.** Respect `prefers-reduced-motion`; no
|
||
auto-updating or auto-dismissing content faster than users can
|
||
perceive it.
|
||
8. **Extend the CI pack.** A new core screen or a new interaction
|
||
pattern gets added to `apps/web/e2e/a11y.spec.ts` (axe, WCAG A/AA
|
||
tags, empty allowlist — additions to the allowlist need a written
|
||
justification in the spec).
|
||
|
||
Code review and issue acceptance criteria treat violations of this
|
||
checklist like functional defects, not polish.
|
||
|
||
## Consequences
|
||
|
||
- New features cost slightly more up front and no longer accumulate an
|
||
accessibility backlog; the July 2026 audit stays the last big one.
|
||
- The axe CI pack fails builds on regressions of the fixed state; specs
|
||
may need locator updates when accessible names are added (a11y labels
|
||
can make `getByLabel` matchers ambiguous — scope them).
|
||
- The full audit report (methodology, per-criterion matrix, measurement
|
||
harness) lives in the operator's workspace
|
||
(`doku/audit-barrierefreiheit-2026-07.md`) and can be re-run after
|
||
larger UI changes.
|