6.1 KiB
Accessibility plan
ARC-16; all PRES groups, with structural priorities E07/E08, J05/J07, W01/W06, C03/C06–C11 and M04. Accessibility is a release criterion per migrated capability, not a final theme polish pass.
Existing evidence and first priorities
Phase 1 carries F14 shared contrast failures and builder preview keyboard-scroll failure after viewport transition. Phase 2 adds behavioral viewport tests, but does not close F14. The original axe suite samples eight routes and can finish before full data/controls load. A green shell scan is not proof of loaded builder/import/send/admin accessibility.
Priority order: (1) semantic foreground/background/focus pairs; (2) named fields/landmarks and modal focus; (3) loaded preview keyboard access and reorder alternatives; (4) complete responsive task traversal and chart alternatives. Fix each at the responsible shared component before multiplying it across screens.
Contracts by interaction
| Area | Required behavior | Evidence required |
|---|---|---|
| Landmarks and headings | Skip link, labelled primary/secondary nav, one main, one h1; sensible heading hierarchy | Real App route transitions, keyboard and accessibility tree |
| Navigation | Active current page, collapsed link names, menu grouping, route-heading focus | Expanded/rail/mobile; close vs navigate focus behavior |
| Fields/errors | Persistent label, help/error association, required status; summary focuses first invalid field; draft retained | RichTextField/Customize selects, date/autocomplete, server validation failure |
| Tables | Table headers/sort state, named row selection/actions, noninteractive text plus explicit links | Keyboard sort/select/bulk; no whole-row click hijacking controls |
| Mobile cards | Same information/actions with translated role/company accessible names | Bokmål long titles, touch/keyboard, no English-only label inheritance |
| Drag/reorder | Move earlier/later or exact status menu for every drag action; pickup/move/drop/cancel announced | CV, checklist, Kanban; focus stays on moved item |
| Dialog/drawer | Labelled purpose, initial focus, trap only when modal, Escape policy, trigger return, dirty confirm | Nested confirmation and mobile software keyboard; no stacked invisible traps |
| Preview | Named scroll region/iframe, meaningful title, keyboard entry/scroll/exit, actual document pagination | Loaded multipage CV, switch desktop→mobile→desktop and zoom |
| AI review | Current/proposed/source names, insert/delete semantics not color alone, deliberate Accept/Reject | Keyboard edited proposal and no-write Reject; long diff/mobile |
| Async states | Busy/loading status, polite completion, actionable error; no repeated announcement per keystroke | Operations, render, import, failed save, delayed read after account switch |
| Charts | Text summary, exact data values table/list, period/denominator/sample, non-color legend | Keyboard access without pointer tooltip; no unreadable SVG-only values |
| Notifications | Accessible unread count, names/timestamps and action names; read ≠ task complete | Popover/full centre, update announcements without focus theft |
| Menus/commands | Search name, result groups/count, selected result, arrow/Enter/Escape behavior | IME, focus return, denied/unavailable commands and no private results after logout |
| Motion | Honor reduced motion; no information relies on animation | Reorder/view/dialog completion under reduced motion |
| Contrast/focus | Internal target: ordinary text ≥4.5:1, large text ≥3:1, essential controls/focus ≥3:1 against adjacent surface | Both modes and states; computed rendered pairs, not swatch-only test |
| Touch/reflow | Aim 44 px touch hit area, visible focus, ordinary content usable at 320 CSS px | 200%/400% zoom, text spacing, forced colors, touch/virtual keyboard |
The numeric thresholds above are project validation targets, not a compliance certification. Disabled controls also need readable adjacent explanations; active important labels cannot use low contrast merely because the design looks quiet.
Loaded-state automated matrix
Use seeded synthetic owner data. Wait for a meaningful named loaded field/row/action, not just body/main. Scan and interact after expanding:
- Career sections, extraction review including low-confidence choices and history.
- CV Content, Customize, AI review, History and long loaded preview.
- Job application drafts, documents, checklist, correspondence, interview and dirty confirmation.
- Inbox draft/send review/uncertain result; Settings security/provider/deletion controls.
- Populated Jobs table/board/cards, saved filters, bulk/trash results.
- Admin data/denial/confirmation and aggregate charts when implemented.
For each migrated shared primitive: EN/NB × light/dark × desktop/phone plus relevant loading/error/locked states. Existing representative browser coverage is a floor, not an instruction to assert only initial pages. Retain all Phase 2 behavior tests and add focused user outcomes rather than CSS snapshots.
Manual validation still required
Use NVDA or Narrator on Windows for primary tasks; record tool/browser, exact route/state, actions and outcome. Verify complete keyboard flow, focus restoration, reading order, data-table alternatives, live-region repetition and escape from iframe/scroll regions. Real touch/virtual keyboard and at least one mobile screen reader require separate access if unavailable locally.
Test a long Norwegian form, many custom statuses, extreme company/title strings, multipage CV, reduced motion, forced colors, browser zoom and increased text spacing. An emulator screenshot does not prove these interactions. Any unavailable manual evidence stays an explicit gap on its PRES trace row.
Stop conditions
No broad component/page propagation while shared naming/focus/contrast regression remains. Do not disable axe rules or hide failed controls to get a green test. P2-D01 must not be disguised by an “empty” loaded-state fixture; its package workflow remains blocked. No public accessibility claim until manual primary-flow evidence exists. F04 production ingress and CI runner gates remain separate.