fix(a11y): name the sliders and the progress bar where the role is

`a11y.md` lists `seek-bar` and `volume-control` under "what is already
correct" because both pass `aria-label`. Measured with
Accessibility.getFullAXTree against the running app on all eleven
views, both sliders compute a name of "": `wa-slider` puts
role="slider" on a div inside its own shadow root, pointing
aria-labelledby at an empty internal <label>, and that IDREF outranks
the host's aria-label. `volume-control` did not have the aria-label the
audit credits it with at all.

The name comes from `label` now, which is the library's own API — and
for a slider that is visible, so `styles/wa-slider-label.css.ts` hides
it by part. Preferred over reaching into the shadow root the way
name-dialog.ts must: if Web Awesome renames the part the label becomes
visible rather than silently nameless. The second rule in that file is
load-bearing — `#slider` takes an 8px margin the moment a label exists,
which grows the bar from 6px to 14px and moves the transport with it.

a11y.25 is the same family: wa-progress-bar maps `label` onto its inner
aria-label, falling back to the localised word "progress" — so it was
named after the widget rather than after the work, not unnamed.

The existing transport test asserted the host's aria-label and called
it an accessible name, so it was pinning the bug.
This commit is contained in:
2026-08-13 01:48:43 -04:00
parent 7410109884
commit b7831e3f15
7 changed files with 232 additions and 4 deletions
@@ -5,6 +5,7 @@ import WaSlider from '@awesome.me/webawesome/dist/components/slider/slider.js';
import { formatSeconds } from '@utils/time';
import { PlayerController } from '@store/controllers/player-controller';
import { designTokens } from '../../../styles/tokens.css';
import { waSliderLabel } from '../../../styles/wa-slider-label.css';
const ProgressIntervalMillis = 1000;
@@ -25,7 +26,7 @@ export class SeekBar extends LitElement {
@state()
private showRemaining: boolean = true;
static override styles = [designTokens, css`
static override styles = [designTokens, waSliderLabel, css`
wa-slider {
--track-size: 6px;
flex: 1;
@@ -210,7 +211,7 @@ export class SeekBar extends LitElement {
<div id="seek-bar-container">
<small data-testid="elapsed-time">${elapsedTime}</small>
<wa-slider
aria-label="Seek"
label="Seek"
.value="${this.seekValue}"
max="${this.trackLength}"
?with-tooltip="${this.hasTrack}"
@@ -5,6 +5,7 @@ import '@awesome.me/webawesome/dist/components/slider/slider.js';
import type WaSlider from '@awesome.me/webawesome/dist/components/slider/slider.js';
import { PlayerController } from '@store/controllers/player-controller';
import { designTokens } from '../../../styles/tokens.css';
import { waSliderLabel } from '../../../styles/wa-slider-label.css';
/** Volume change (0-100) applied per scroll-wheel tick. */
const WHEEL_STEP = 5;
@@ -28,7 +29,7 @@ export class VolumeControl extends LitElement {
@state()
private pendingVolume: number | null = null;
static override styles = [designTokens, css`
static override styles = [designTokens, waSliderLabel, css`
:host {
position: relative;
display: inline-flex;
@@ -209,6 +210,7 @@ export class VolumeControl extends LitElement {
@click="${this.handlePopupClick}"
>
<wa-slider
label="Volume"
orientation="vertical"
min="0"
max="100"
+1
View File
@@ -268,6 +268,7 @@ export class JobRow extends LitElement {
return html`
<wa-progress-bar
label=${job.title}
value=${progressPercent(job) ?? 0}
></wa-progress-bar>
`;