Skip to content

Commit 186d5b4

Browse files
committed
fix(a11y): add landmark role, aria-pressed toggles, error alerts, and dynamic screen reader labels
- Add role="region" aria-label="Podcast Player" landmark on player shell - Add aria-pressed on play and mute toggle buttons (updated on state change) - Add role="alert" on error message for screen reader interruption - Add aria-valuetext on progress bar ("{current} of {duration}") - Update poster alt text dynamically to include episode title - Update rate button aria-label with current speed value
1 parent 9921ed5 commit 186d5b4

1 file changed

Lines changed: 13 additions & 5 deletions

File tree

assets/js/podcast-player.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ class PodcastPlayer extends HTMLElement {
312312
.btn:focus-visible, .chapter-chip:focus-visible, input[type="range"]:focus-visible { outline: none; box-shadow: var(--pp-focus-ring); }
313313
[hidden] { display: none !important; }
314314
</style>
315-
<div class="player" part="player">
315+
<div class="player" part="player" role="region" aria-label="Podcast Player">
316316
<div class="header" part="header">
317317
<img class="poster" part="poster" src="" alt="Cover" hidden>
318318
<div class="info">
@@ -324,13 +324,13 @@ class PodcastPlayer extends HTMLElement {
324324
<button class="btn btn-skip-back" part="skip-back-btn"
325325
title="Rewind 15s" aria-label="Rewind 15 seconds">⏪</button>
326326
<button class="btn btn-play" part="play-btn"
327-
title="Play" aria-label="Play">▶</button>
327+
title="Play" aria-label="Play" aria-pressed="false">▶</button>
328328
<button class="btn btn-skip-fwd" part="skip-fwd-btn"
329329
title="Forward 15s" aria-label="Forward 15 seconds">⏩</button>
330330
<div class="progress-wrap" part="progress-wrap">
331331
<input type="range" class="progress" part="progress"
332332
min="0" max="100" value="0"
333-
aria-label="Seek position">
333+
aria-label="Seek position" aria-valuetext="0:00 of 0:00">
334334
</div>
335335
<span class="time time-current" part="time-current">--:--</span>
336336
<span class="time time-sep" part="time-sep">/</span>
@@ -339,7 +339,7 @@ class PodcastPlayer extends HTMLElement {
339339
<div class="extras" part="extras">
340340
<div class="vol-wrap" part="vol-wrap">
341341
<button class="btn btn-mute" part="mute-btn"
342-
title="Mute" aria-label="Toggle mute">🔊</button>
342+
title="Mute" aria-label="Toggle mute" aria-pressed="false">🔊</button>
343343
<input type="range" class="volume" part="volume"
344344
min="0" max="1" step="0.05" value="1"
345345
aria-label="Volume">
@@ -348,7 +348,7 @@ class PodcastPlayer extends HTMLElement {
348348
title="Playback speed" aria-label="Playback speed">1×</button>
349349
<div class="chapters" part="chapters" hidden></div>
350350
</div>
351-
<div class="error-msg" part="error" hidden></div>
351+
<div class="error-msg" part="error" role="alert" hidden></div>
352352
</div>
353353
`;
354354

@@ -488,6 +488,8 @@ class PodcastPlayer extends HTMLElement {
488488
if (val) {
489489
this._els.poster.src = val;
490490
this._els.poster.hidden = false;
491+
const title = this.getAttribute("title") || "";
492+
this._els.poster.alt = title ? `Cover: ${title}` : "Cover";
491493
} else {
492494
this._els.poster.src = "";
493495
this._els.poster.hidden = true;
@@ -584,6 +586,7 @@ class PodcastPlayer extends HTMLElement {
584586
_toggleMute() {
585587
this._audio.muted = !this._audio.muted;
586588
this._updateMuteIcon(this._audio.muted ? 0 : this._audio.volume);
589+
this._els.muteBtn.setAttribute("aria-pressed", this._audio.muted ? "true" : "false");
587590
}
588591

589592
_updateMuteIcon(vol) {
@@ -608,6 +611,7 @@ class PodcastPlayer extends HTMLElement {
608611
const next = rates[(idx + 1) % rates.length];
609612
this._audio.playbackRate = next;
610613
this._els.rateBtn.textContent = next + "×";
614+
this._els.rateBtn.setAttribute("aria-label", `Playback speed ${next}×`);
611615
}
612616

613617
/* ------------------------------------------------------------------ */
@@ -620,6 +624,8 @@ class PodcastPlayer extends HTMLElement {
620624
this._els.progress.value = pct;
621625
this._els.progress.style.setProperty("--progress", pct + "%");
622626
this._els.timeCurrent.textContent = this._fmtTime(this._audio.currentTime);
627+
this._els.progress.setAttribute("aria-valuetext",
628+
`${this._fmtTime(this._audio.currentTime)} of ${this._fmtTime(this._audio.duration)}`);
623629

624630
// Highlight active chapter
625631
this._updateActiveChapter();
@@ -665,6 +671,7 @@ class PodcastPlayer extends HTMLElement {
665671
_onPlay() {
666672
this._els.playBtn.textContent = "⏸";
667673
this._els.playBtn.setAttribute("aria-label", "Pause");
674+
this._els.playBtn.setAttribute("aria-pressed", "true");
668675
this._els.playBtn.title = "Pause";
669676
this._dispatchState();
670677
this._updateMediaSessionPlayback();
@@ -679,6 +686,7 @@ class PodcastPlayer extends HTMLElement {
679686
_onPause() {
680687
this._els.playBtn.textContent = "▶";
681688
this._els.playBtn.setAttribute("aria-label", "Play");
689+
this._els.playBtn.setAttribute("aria-pressed", "false");
682690
this._els.playBtn.title = "Play";
683691
this._dispatchState();
684692
this._updateMediaSessionPlayback();

0 commit comments

Comments
 (0)