33** Date:** 2026-06-14
44** Branch:** ` kpoin/ui-accessibility `
55** Scope:** ` prototype/ui-redesign/ ` only
6- ** Status:** Phase 1 ✅ complete, Phase 2 ✅ mostly complete (items 16–18 deferred to Phase 3)
7- ** Test status (2026-06-15 ):** All 50 automated tests passing, 7 skipped, 0 failed on ` kpoin/ui-testing `
6+ ** Status:** Phase 1 ✅ complete, Phase 2 ✅ mostly complete (items 16–18 deferred to Phase 3), Phase 3 (GUI3 preset a11y) ✅ complete
7+ ** Test status (2026-06-22 ):** All 61 automated tests passing, 7 skipped, 0 failed on ` feat/gui3-presets-a11y `
88
99---
1010
1111## Summary Table
1212
13- | # | Item | Section | Priority | Effort |
14- | ---| ------| ---------| ----------| --------|
15- | 1 | ` <main> ` landmark | Standard A11y | ** P0** | S |
16- | 2 | ` div.onClick ` → ` <button> ` | Standard A11y | ** P0** | M |
17- | 3 | Focus rings (global ` outline: none ` ) | Standard A11y | ** P0** | S |
18- | 4 | Composer textarea ` aria-label ` | Standard A11y | ** P0** | S |
19- | 5 | Skip-to-main link | Standard A11y | ** P0** | S |
20- | 6 | Preset slideover focus trap + ESC | Standard A11y | ** P0** | M |
21- | 7 | ` aria-live ` for streaming output | Standard A11y | ** P0** | M |
22- | 8 | ARIA landmarks audit (nav, complementary) | Standard A11y | P1 | S |
23- | 9 | ` titlebar__status-dot ` screen reader label | Standard A11y | P1 | S |
24- | 10 | Persistence-toggle label (` ChatView.tsx:1725 ` ) | Standard A11y | P1 | S |
25- | 11 | Preset slideover unlabeled inputs | Standard A11y | P1 | S |
26- | 12 | Color contrast audit (both themes) | Standard A11y | P1 | M |
27- | 13 | ` prefers-reduced-motion ` (all animations) | LLM-specific | ** P0** | M |
28- | 14 | Font size / text scale controls | LLM-specific | P1 | M |
29- | 15 | High-contrast theme mode | LLM-specific | P1 | L |
30- | 16 | Keyboard shortcut system | LLM-specific | P1 | M |
31- | 17 | Response verbosity setting | LLM-specific | P2 | M |
32- | 18 | Dyslexia-friendly font option | LLM-specific | P2 | S |
33- | 19 | Message role announcements for screen readers | LLM-specific | P2 | S |
13+ | # | Item | Section | Priority | Effort | Status |
14+ | ---| ------| ---------| ----------| --------| --------|
15+ | 1 | ` <main> ` landmark | Standard A11y | ** P0** | S | ✅ Done |
16+ | 2 | ` div.onClick ` → ` <button> ` | Standard A11y | ** P0** | M | ✅ Done (PresetCard) |
17+ | 3 | Focus rings (global ` outline: none ` ) | Standard A11y | ** P0** | S | ✅ Done |
18+ | 4 | Composer textarea ` aria-label ` | Standard A11y | ** P0** | S | ✅ Done |
19+ | 5 | Skip-to-main link | Standard A11y | ** P0** | S | ✅ Done |
20+ | 6 | Preset slideover focus trap + ESC | Standard A11y | ** P0** | M | ✅ Done |
21+ | 7 | ` aria-live ` for streaming output | Standard A11y | ** P0** | M | ✅ Done |
22+ | 8 | ARIA landmarks audit (nav, complementary) | Standard A11y | P1 | S | ✅ Done |
23+ | 9 | ` titlebar__status-dot ` screen reader label | Standard A11y | P1 | S | ✅ Done |
24+ | 10 | Persistence-toggle label (` ChatView.tsx:1725 ` ) | Standard A11y | P1 | S | ✅ Done |
25+ | 11 | Preset slideover unlabeled inputs | Standard A11y | P1 | S | ✅ Done |
26+ | 12 | Color contrast audit (both themes) | Standard A11y | P1 | M | |
27+ | 13 | ` prefers-reduced-motion ` (all animations) | LLM-specific | ** P0** | M | ✅ Done |
28+ | 14 | Font size / text scale controls | LLM-specific | P1 | M | |
29+ | 15 | High-contrast theme mode | LLM-specific | P1 | L | |
30+ | 16 | Keyboard shortcut system | LLM-specific | P1 | M | |
31+ | 17 | Response verbosity setting | LLM-specific | P2 | M | |
32+ | 18 | Dyslexia-friendly font option | LLM-specific | P2 | S | |
33+ | 19 | Message role announcements for screen readers | LLM-specific | P2 | S | |
34+ | 20 | Preset param controls programmatic labels (#2338 ) | GUI3 Presets | ** P0** | S | ✅ Done 2026-06-22 |
35+ | 21 | Backend/device fields discoverable (#2339 ) | GUI3 Presets | ** P0** | S | ✅ Done 2026-06-22 |
36+ | 22 | Preset card exposes metadata to AT (#2345 ) | GUI3 Presets | ** P0** | S | ✅ Done 2026-06-22 |
37+ | 23 | Capability chip radio semantics (#2350 ) | GUI3 Presets | ** P0** | S | ✅ Done 2026-06-22 |
38+ | 24 | AutoOpt run selection state (#2352 ) | GUI3 Presets | ** P0** | S | ✅ Done 2026-06-22 |
3439
3540---
3641
@@ -471,13 +476,23 @@ Do these first. All are small changes with high compliance impact.
47147617 . ** 2.1** — Add ` --font-scale ` token + A−/A+ UI control — DEFERRED to Phase 3
47247718 . ** 1.1.3** — Convert message list to ` <ol> ` with ` <article> ` per message — DEFERRED to Phase 3
473478
474- ### Phase 3 — Enhancements (L-effort, P2, new deps)
479+ ### Phase 3 — Enhancements (L-effort, P2, new deps) + GUI3 Preset A11y
475480
47648119 . ** 2.2** — High-contrast theme (` [data-theme="high-contrast"] ` + ` forced-colors ` handling) — new token set
47748220 . ** 2.6** — Dyslexia-friendly font (Lexend self-hosted font files — new asset dep)
47848321 . ** 2.4** — Response verbosity preference in composer toolbar
47948422 . ** 2.8** — Full message role announcement polish (combined with Phase 2 article work)
480485
486+ #### GUI3 Preset A11y — ✅ DONE 2026-06-22 (branch ` feat/gui3-presets-a11y ` )
487+
488+ All five items from the blind NVDA screen-reader user's feedback on UI 3 beta:
489+
490+ 23 . ** #2338 ** ✅ DONE — All Preset parameter controls labelled via ` htmlFor ` /` id ` (temperature, top_p, context size, top_k, repeat penalty, steps, CFG scale, engine hint, AutoOpt result, llamacpp_args, sdcpp_args) and via ` aria-label ` (image width, image height which share one visual label). File: ` PresetManager.tsx ` lines ~ 1000–1075.
491+ 24 . ** #2339 ** ✅ DONE — ` llamacpp_backend ` and ` llamacpp_device ` converted to ` <input list=> ` + ` <datalist> ` exposing known values (backends: auto/cpu/cuda/vulkan/kompute/metal/rpc/opencl/mmap; devices: Auto/CPU/CUDA0/CUDA1/Vulkan0/Vulkan1/Metal). File: ` PresetManager.tsx ` lines ~ 1060–1067.
492+ 25 . ** #2345 ** ✅ DONE — PresetCard overlay button gains ` aria-describedby ` pointing to a ` sr-only ` span containing: starter/manual-args state, applies_to capability list, parameter summary, prompt name, tools state. File: ` PresetManager.tsx ` lines ~ 700–726.
493+ 26 . ** #2350 ** ✅ DONE — Capability chip container gains ` role="radiogroup" aria-label="Applies to capabilities" ` ; each chip button gains ` role="radio" aria-checked={…} ` . File: ` PresetManager.tsx ` lines ~ 937–943.
494+ 27 . ** #2352 ** ✅ DONE — AutoOpt run buttons gain ` aria-pressed={selectedAutoRunId === run.id} ` , updated on selection change. File: ` PresetManager.tsx ` line ~ 528.
495+
481496---
482497
483498## Running the Accessibility Tests
@@ -510,7 +525,7 @@ npm test
510525
511526> Playwright's ` webServer ` config in ` playwright.config.ts ` starts ` npm run dev ` automatically if nothing is already listening on port 8080. If you already have the dev server running, it reuses it (` reuseExistingServer: true ` ).
512527
513- ### Test groups (34 tests)
528+ ### Test groups (61 tests)
514529
515530| Group | Tests | What it checks |
516531| -------| -------| ----------------|
@@ -523,11 +538,16 @@ npm test
523538| aria-live regions | A25–A27 | Assertive + polite regions in DOM at load; both are ` .sr-only ` |
524539| : focus-visible rings | A28–A30 | Keyboard = outline present; mouse click = no ring; textarea keyboard ring present |
525540| prefers-reduced-motion | A31–A34 | Bottom sheet transition near-zero; normal = 280ms; all transitions; ` transform: none ` snap |
541+ | Preset param labels (#2338 ) | A35–A37 | temperature/ctx-size/top_k sliders labelled via htmlFor/id |
542+ | Backend/device discoverable (#2339 ) | A38–A39 | llamacpp_backend and llamacpp_device inputs have datalist with ≥3 options |
543+ | Preset card metadata (#2345 ) | A40 | Card button aria-describedby includes applies_to, prompt, tools |
544+ | Capability radio semantics (#2350 ) | A41–A43 | Container has role=radiogroup; buttons have role=radio + aria-checked; exactly 1 checked |
545+ | AutoOpt selection state (#2352 ) | A44–A45 | aria-pressed exposed; updates on click |
526546
527547### Known limitation
528548
529549Tests A25–A27 only verify that the aria-live regions ** exist** . Verifying that the polite region receives debounced content during streaming requires mocking ` POST /api/v1/chat/completions ` with a chunked SSE response via ` page.route() ` . That mock infrastructure is tracked as a TODO in the test file.
530550
531551---
532552
533- * Last updated: 2026-06-14 by Mattingly*
553+ * Last updated: 2026-06-22 by Mattingly (GUI3 preset a11y items # 2338 # 2339 # 2345 # 2350 # 2352 ) *
0 commit comments