Skip to content

Commit 33a113a

Browse files
authored
fix(vimeo): a11y keyboard and video placeholder alt text (#803)
1 parent 4ed9c62 commit 33a113a

2 files changed

Lines changed: 32 additions & 5 deletions

File tree

‎packages/script/src/runtime/components/ScriptVimeoPlayer.vue‎

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,16 +253,43 @@ watch(status, (status) => {
253253
}
254254
})
255255
256+
// Keyboard accessibility: dispatch the configured trigger event on Enter/Space
257+
// so users navigating via keyboard can activate the placeholder.
258+
const keyboardTriggerable =computed(() => {
259+
if (ready.value)
260+
returnfalse
261+
const triggers =Array.isArray(props.trigger) ?props.trigger: [props.trigger]
262+
returntriggers.some(t=>typeoft==='string'&&!['immediate', 'onNuxtReady', 'visibility', 'visible'].includes(t))
263+
})
264+
265+
function onPlaceholderKeydown(e:KeyboardEvent) {
266+
if (e.key!=='Enter'&&e.key!=='')
267+
return
268+
e.preventDefault()
269+
if (!rootEl.value)
270+
return
271+
const triggers = (Array.isArray(props.trigger) ?props.trigger: [props.trigger]).filter(Boolean) asstring[]
272+
for (const t oftriggers) {
273+
if (typeoft!=='string')
274+
continue
275+
if (['immediate', 'onNuxtReady', 'visibility', 'visible'].includes(t))
276+
continue
277+
rootEl.value.dispatchEvent(newEvent(t, { bubbles: false }))
278+
}
279+
}
280+
256281
const rootAttrs =computed(() => {
282+
const interactive =keyboardTriggerable.value
257283
returndefu(props.rootAttrs, {
258284
'aria-busy': status.value==='loading',
259285
'aria-label': status.value==='awaitingLoad'
260-
?'Vimeo Player - Placeholder'
286+
?(interactive?'Play video':'Vimeo Player - Placeholder')
261287
:status.value==='loading'
262288
?'Vimeo Player - Loading'
263289
:'Vimeo Player - Loaded',
264290
'aria-live': 'polite',
265-
'role': 'application',
291+
'role': interactive?'button':'application',
292+
'tabindex': interactive?0:undefined,
266293
'style': {
267294
'--vimeo-ratio': props.ratio,
268295
'maxWidth': '100%',
@@ -279,7 +306,7 @@ const rootAttrs = computed(() => {
279306
const placeholderAttrs =computed(() => {
280307
returndefu(props.placeholderAttrs, {
281308
src: placeholder.value,
282-
alt: '',
309+
alt: 'Play video',
283310
loading: props.aboveTheFold?'eager':'lazy',
284311
// @ts-expect-error untyped
285312
fetchpriority: props.aboveTheFold?'high':undefined,
@@ -296,7 +323,7 @@ onBeforeUnmount(() => player?.unload())
296323
</script>
297324

298325
<template>
299-
<divref="rootEl"v-bind="rootAttrs">
326+
<divref="rootEl"v-bind="rootAttrs"@keydown="keyboardTriggerable ? onPlaceholderKeydown($event) : undefined">
300327
<divv-show="ready"ref="elVimeo"class="vimeo-player" />
301328
<slotv-if="!ready"v-bind="payload":placeholder="placeholder"name="placeholder">
302329
<imgv-if="placeholder"v-bind="placeholderAttrs">

‎packages/script/src/runtime/components/ScriptYouTubePlayer.vue‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ if (import.meta.server) {
245245
const placeholderAttrs =computed(() => {
246246
returndefu(props.placeholderAttrs, {
247247
src: isFallbackPlaceHolder.value?fallbackPlaceHolder.value:placeholder.value,
248-
alt: '',
248+
alt: 'Play video',
249249
loading: props.aboveTheFold?'eager':'lazy',
250250
// @ts-expect-error untyped
251251
fetchpriority: props.aboveTheFold?'high':undefined,

0 commit comments

Comments
 (0)