WCAG 2.2 AA audit fixes + dependent-settings gating - #10
Merged
Conversation
2.5.8 Target Size
- Progress seek slider: expand interactive hit area to 24 px via
transparent height; 6 px visual bar rendered by ::before pseudo-element
- Range slider thumbs: 18 px → 24 px (webkit + moz)
- Cue marks re-centred with top:50%/translateY(-50%) in expanded track
1.4.11 Non-text Contrast
- Badge border: var(--border) (#0f3460, 1.3:1) → var(--badge-border)
(#4d7eb5, 3.76:1 on --bg-card); new CSS variable added to :root
4.1.2 Name/Role/Value — aria-disabled misuse
- #disc-every initial HTML state: aria-disabled="true" → disabled attribute
- app.js + settings-panel.js: setAttribute("aria-disabled") →
discEvery.disabled = !on; so native input correctly blocks interaction
1.3.1 Info and Relationships
- Added aria-describedby to every settings control that lacked it:
preset-select, transition-select, harmonic-mode, dj-beatmatch,
dj-phrase-align, dj-outro-intro, pb-eq-duck, pb-anchor-seed,
pb-show-lyrics, pb-replaygain, pb-daypart, pb-mood-arc,
pb-mood-arc-hours, pb-import-cues, pb-beat-sync-fx, pb-key-sync-fx,
pb-beatmatch-on-skip, audio-device, pb-transition-mode, pb-crossfade,
pb-fade-in, bpm-lo, bpm-hi, disc-enabled, disc-every
<summary><h2> double-announcement
- Removed <h2> from every <details> summary; heading appearance (1.1 rem,
600 weight, uppercase, letter-spacing, text-dim colour) applied directly
to details.card > summary via CSS
- details/section aria-labelledby attrs updated: panels now reference tab
button IDs (tab-now, tab-settings, tab-queue, tab-library) rather than
the removed heading IDs; EQ group retains its reference via id moved to
<summary id="eq-heading">
- tabs.js focus management: falls back to first <summary> when no <h2>
exists in the newly-activated panel
Expand/collapse arrow AT suppression
- details.card > summary::after content uses CSS alt-text syntax
content: "\25B8" / "" so the ▸/▾ glyph is hidden from screen reader
speech (expanded/collapsed state already announced by disclosure widget)
Misc
- Remove redundant role="main" from <main>
- Replace duplicate .sr-only with .visually-hidden on #hist-goto label
and #sr-status; remove the now-dead .sr-only CSS block
- <section> tabpanel labels consistently use tab button IDs throughout
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e help text - Add data-show-when="disc-enabled" to the Every-N-tracks row so it collapses when the checkbox is unchecked (matches mood-arc-hours pattern) - Remove outdated sentence referencing a Discovery button on the Now Playing tab; btn-discovery is display:none and no longer surfaced Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extend show-when.js to support `data-show-when="selectId=value"` so elements can be gated on a specific select option, not just a checkbox. Single delegated listener now covers both input[type=checkbox] and select. Wire key-prefer-flats row + its desc to data-show-when="key-notation=musical" so both collapse when Camelot notation is active. Label trimmed from "Use flats (musical mode)" to "Use flats" and description drops the now- redundant "Only used when key notation is set to Musical" sentence. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n WS push
- Add `[hidden] { display: none !important }` so the `data-show-when`
mechanism actually hides .settings-row (flex) and .setting-desc
(block) targets. Author display rules outrank the UA
`[hidden] { display: none }` on specificity, which let the Use-flats /
mood-arc-hours / disc-every / liner-fieldset rows stay visible even
with the `hidden` attribute correctly set.
- Call `applyShowWhen()` at end of `applySettingsState` so WS state
pushes that set select values programmatically (key-notation,
pb-pick-mode, etc.) re-evaluate visibility. The delegated `change`
listener never fires for programmatic .value writes, so without this
the show-when state was frozen to whatever the HTML defaults were at
page load.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR bundles a WCAG 2.2 AA audit pass on the web UI together with a follow-up round of settings-panel UX improvements (dependent-control gating).
Accessibility (WCAG 2.2 AA)
::beforepseudo-element. Range slider thumbs grew from 18 px to 24 px (webkit + moz). Cue marks on the progress bar were re-centred so they stay aligned in the expanded track.--border(#0f3460), which only achieved 1.3:1 against the card background. A new--badge-bordertoken (#4d7eb5) brings that to 3.76:1 on--bg-card, which passes the 3:1 minimum for UI components.aria-disabled="true", which does not actually block keyboard or pointer interaction. Switched to the nativedisabledattribute on#disc-everyso the input is genuinely inert when discovery is off.aria-describedbyreferences to twenty-five settings controls that were missing them, so the existing inline help text is now programmatically associated with its field instead of being purely visual.<summary>/<h2>double announcement — Every<details><summary>previously wrapped its label in<h2>, which screen readers announced once as a heading and once as a disclosure widget. Removed the inner<h2>and reapplied the heading look (1.1 rem, 600 weight, uppercase, letter-spaced, dim foreground) directly viadetails.card > summaryCSS. Sectionaria-labelledbyreferences now point at the corresponding tab IDs (tab-nowetc.) so each tabpanel is still labelled. The EQ group retains its label viaid="eq-heading"moved onto its summary.▸/▾glyph in the summary::afteris now suppressed from assistive-tech speech using the CSS alt-text syntaxcontent: "\25B8" / "". The disclosure widget already announces expanded / collapsed state, so the glyph is purely visual.role="main"from<main>, consolidated the duplicate.sr-onlyclass onto.visually-hidden, and dropped the now-dead.sr-onlyblock.Settings UX — dependent-control gating
show-when.jsto recognise aselectId=valueform ondata-show-when, in addition to the existing checkbox form.[hidden] { display: none !important }rule was added toapp.css. Without it,.settings-row { display: flex }and.setting-desc { display: block }outranked the user-agent[hidden] { display: none }rule on specificity, so JS-sethiddenattributes had no visual effect — the dependent rows stayed visible even though the JS logic was correct.applyShowWhen()is now called at the end ofapplySettingsState. Previously the delegatedchangelistener was the only path that re-evaluated visibility, but WebSocket state pushes set select values programmatically (.value = ...), which does not firechange, so the show-when state was effectively frozen to whatever the HTML defaults were at page load.Test plan
applyShowWhen()call).role=progressbarwith a meaningfularia-valuetext, and the hit target should be at least 24 px tall.#4d7eb5border with at least 3:1 contrast against the card background.Generated with Claude Code.