diff --git a/packages/vidstack/src/components/player.ts b/packages/vidstack/src/components/player.ts index 3465c114a..4be77b8d9 100644 --- a/packages/vidstack/src/components/player.ts +++ b/packages/vidstack/src/components/player.ts @@ -268,17 +268,15 @@ export class MediaPlayer #skipTitleUpdate = false; #watchTitle() { const el = this.$el, + { ariaLabel } = this.$props, { title, live, viewType, providedTitle } = this.$state, isLive = live(), type = uppercaseFirstChar(viewType()), typeText = type !== 'Unknown' ? `${isLive ? 'Live ' : ''}${type}` : isLive ? 'Live' : 'Media', - currentTitle = title(); + currentTitle = title(), + label = ariaLabel() || `${typeText} Player` + (currentTitle ? ` - ${currentTitle}` : ''); - setAttribute( - this.el!, - 'aria-label', - `${typeText} Player` + (currentTitle ? ` - ${currentTitle}` : ''), - ); + setAttribute(this.el!, 'aria-label', label); // Title attribute is removed to prevent popover interfering with user hovering over player. if (!__SERVER__ && el?.hasAttribute('title')) { diff --git a/packages/vidstack/src/core/api/player-props.ts b/packages/vidstack/src/core/api/player-props.ts index 76a7ebac8..3f448e007 100644 --- a/packages/vidstack/src/core/api/player-props.ts +++ b/packages/vidstack/src/core/api/player-props.ts @@ -13,6 +13,7 @@ import type { MediaLoadingStrategy, MediaPosterLoadingStrategy } from './types'; export const mediaPlayerProps: MediaPlayerProps = { artist: '', artwork: null, + ariaLabel: '', autoplay: false, autoPlay: false, clipStartTime: 0, @@ -58,6 +59,8 @@ export interface MediaStateAccessors extends Pick< export type PlayerSrc = MediaSrc | MediaSrc[]; +export type MediaPlayerAriaLabel = string; + export interface MediaPlayerProps // Prefer picking off the `MediaStore` type to ensure docs are kept in-sync. extends Pick< @@ -84,6 +87,11 @@ export interface MediaPlayerProps | 'liveEdgeTolerance' | 'minLiveDVRWindow' > { + /** + * A custom ARIA label for the player root. By default, the player will generate a label using + * the current media type, live state, and title. + */ + ariaLabel: MediaPlayerAriaLabel; /** @deprecated - Use `autoPlay` */ autoplay: boolean; /** @deprecated - Use `crossOrigin` */ diff --git a/packages/vidstack/src/elements/define/player-element.ts b/packages/vidstack/src/elements/define/player-element.ts index 5027f2dc6..0a5d8e6ab 100644 --- a/packages/vidstack/src/elements/define/player-element.ts +++ b/packages/vidstack/src/elements/define/player-element.ts @@ -18,6 +18,7 @@ export class MediaPlayerElement extends Host(HTMLElement, MediaPlayer) { static tagName = 'media-player'; static override attrs: Attributes = { + ariaLabel: 'aria-label', autoPlay: 'autoplay', crossOrigin: 'crossorigin', playsInline: 'playsinline',