Skip to content

Panel accessibility: every control has a name, keyboard focus is visible (#777) - #787

Merged
CaYatur merged 1 commit into
mainfrom
a11y/control-names-777
Oct 20, 2026
Merged

CaYatur merged 1 commit into
mainfrom
a11y/control-names-777

Conversation

@CaYatur

@CaYatur CaYatur commented Oct 20, 2026

Copy link
Copy Markdown
Owner

Part of #777, section 4.

Measured

  • Names: I read Chromium's accessibility tree with Accessibility.getFullAXTree in every category, with folds open and a populated profile. 139 interactive controls had no name: 54 sliders, 53 switches/checkboxes, 21 selects, 6 number boxes and 4 text boxes. A screen reader announced only "slider". The cause: .ctrl > label.lbl was never tied to its control.
  • Focus: I pressed real Tab keys through every category (Input.dispatchKeyEvent) and compared each focused element's computed look with an unfocused snapshot. 68 of 606 elements showed no change:
    • range inputs: outline: none, and the thumb changed only on hover;
    • 7 selects in the export and update cards: an inline style.cssText border overrode select:focus;
    • the lighting picker wrapper.

Change

  • A MutationObserver in admin.js:
    • moves each row's label text into span.lbl-t and points the row's unnamed controls at it with aria-labelledby;
    • keeps the reset button inside the label out of the name;
    • names controls after the translated text node itself, so the name switches language with it;
    • falls back to the preceding .group-label.
  • It runs directly in the observer callback. I first used requestAnimationFrame, which never fires in a background window: the self-test caught that.
  • Controls with their own layout got their own names (Turkish, translated through i18n): the A/B crossfader, the Smart Silence Filter, the MCP port, and the timeline BPM, beats-per-bar and snapping controls.
  • Focus styles: input[type=range]:focus-visible (outline plus thumb ring) and .lighting-select-wrap:focus-visible. The select's inline style moved to a sel-ctrl class, so select:focus applies.

Verified

  • Probe again after the fix: 1014 interactive nodes, 0 unnamed in both Turkish and English. Sample English names: "Sensitivity", "Smart Silence Filter". Tab walk: 606 elements, 0 without a visible focus change.
  • New self-test step: it reads the accessibility tree and Tabs through every category on the populated panel from Self-test: scan a populated panel for translation and contrast (#777) #785. It fails on any unnamed control or unchanged focus, and also if fewer than 500 named controls or 300 focusable elements were seen.
    • Isolated profile: 872 named, 595 focused, PASS.
    • Earlier runs of the same step caught the rAF issue (139 unnamed) and three timeline toolbar controls, both fixed here.
  • npm test: 3238 passed (tests/a11y-panel.test.js, +4).
  • The theme contrast step is unchanged: about 3,040 texts per theme, none below the threshold. The layout was checked by screenshot.

…ble; self-test guards both (#777)

Chromium's accessibility tree showed 139 unnamed controls (54 sliders, 53 switches, 21 lists, number and text boxes): each .ctrl had a label.lbl that was not tied to its control. A MutationObserver (direct, not rAF - rAF never runs in a background window) moves the label's text into span.lbl-t and points unnamed controls in the row at it with aria-labelledby, so the reset button stays out of the name and the translated text node is the name. Rows without a label use the preceding .group-label. Own names for the crossfader, Smart Silence Filter, MCP port and the timeline BPM/beats/snapping controls (EN strings added).

Tabbing through the panel reached 606 elements; 68 showed no focus: range inputs (outline none, thumb changed only on hover), the export/update selects (an inline border overrode select:focus; now class sel-ctrl) and the lighting picker. Focus-visible styles added.

Self-test: reads the accessibility tree per category with folds open and Tabs through every category; fails on unnamed controls or unchanged focus. Isolated profile: 872 named controls, 595 focusable elements, PASS. Tests 3238.

Co-authored-by: caganturgut <271973834+caganturgut@users.noreply.github.com>
@CaYatur
CaYatur merged commit f698e16 into main Oct 20, 2026
5 checks passed
@CaYatur
CaYatur deleted the a11y/control-names-777 branch October 20, 2026 03:57
@cayadraft

cayadraft Bot commented Oct 20, 2026

Copy link
Copy Markdown

@CaYatur

CaYaDraft — pull request

Summary
Panel accessibility: every control has a name, keyboard focus is visible (#777)

Files
CHANGELOG.md (modified, +20/-0)
@@ -72,6 +72,26 @@ updater sees v3.1.5 as the latest release and does not offer it to the beta as a

  • The selected scene's info line was 3.9:1 in Light and 4.1–4.4:1
    in Midnight and CaYaDev. On the selected row's accent tint it now uses the secondary text
    colour, and the contrast rules cover body and secondary text on selected rows.
    +- Screen readers and keyboards [777].
    • Chrom…

README.md (modified, +2/-2)
@@ -17,7 +17,7 @@ layers and 40 GPU effects, an OBS overlay, Spout / Syphon, **project
Downloads
License: MIT
[![Platform](https://img.shields.io/badge/platform-Windows%20%…

README.tr.md (modified, +2/-2)
@@ -18,7 +18,7 @@ destesi**, ve MCP üzerinden yapay zekâ kontrolü.
İndirme
Lisans: MIT
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-111997.sv…

ROADMAP.md (modified, +1/-1)
@@ -133,7 +133,7 @@ npm test
npm start -- --smoke


-- **3234 unit tests, all passing** on `main`. 703 of those shipped in v3.1.0;
+- **3238 unit tests, all passing** on `main`. 703 of those shipped in v3.1.0;
  105 came with v3.1.1; 163 came with v3.1.2; 157 came with v3.1.3 — 1128 at
  that tag — 469 more with v3.1.4, most of them from the MilkDrop work — 1597 at
  that tag — 1402 more…

src/admin/admin.css (modified, +8/-0)
@@ -508,6 +508,8 @@ body {
  position: relative; font-size: 12px; color: var(--text);
  display: flex; align-items: center; gap: 6px; padding-right: 20px;
}
+/* Erişilebilir adın metni (#777): etiketin iç düzeni değişmesin */
+.ctrl label.lbl > .lbl-t { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.ctrl .val {
  font-size: 11px; color: var(--muted); min-width: 46px; t…

src/admin/admin.js (modified, +61/-2)
@@ -280,6 +280,64 @@
    hidden: 1, required: 1, open: 1, autofocus: 1, novalidate: 1,
  };

+  /* ERİŞİLEBİLİR ADLAR (#777). Ayar satırı `.ctrl` içinde bir `label.lbl`
+     ve bir denetim, ama etiket denetime bağlı değildi: Chromium'un
+     erişilebilirlik ağacında 139 denetimin (54 kay…

**Note**
The local model is unavailable, so this is only the title and file list.

---
Stopping here. I will not merge, push, or change this pull request until you ask.

`/caya explain` describes the diff. `/caya plan` previews the next edit. `/caya revise` adds a commit.

<!-- cayadraft -->

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant