From 25e50a73f712771ebd00179abe2acdebe80ab0b4 Mon Sep 17 00:00:00 2001
From: joshuasosa <4400438+joshuasosa@users.noreply.github.com>
Date: Thu, 16 Apr 2026 11:07:58 -0700
Subject: [PATCH 1/2] Update text on media video play/pause buttons.
---
.../js/az_paragraphs_az_text_media_vimeo.js | 62 ++++++++-----------
.../js/az_paragraphs_az_text_media_youtube.js | 36 ++++++-----
...--az-remote-video--az-background.html.twig | 3 +-
.../css/az_paragraphs_az_text_media.css | 7 ---
4 files changed, 49 insertions(+), 59 deletions(-)
diff --git a/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_vimeo.js b/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_vimeo.js
index 7ae28021bc..c653f8b152 100644
--- a/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_vimeo.js
+++ b/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_vimeo.js
@@ -67,26 +67,6 @@
}
}
- // Helper function for play button click
- function handlePlayButtonClick(element, parentParagraph) {
- return (event) => {
- event.preventDefault();
- element.player.play().catch((error) => vimeoError(error));
- parentParagraph.classList.add('az-video-playing');
- parentParagraph.classList.remove('az-video-paused');
- };
- }
-
- // Helper function for pause button click
- function handlePauseButtonClick(element, parentParagraph) {
- return (event) => {
- event.preventDefault();
- element.player.pause().catch((error) => vimeoError(error));
- parentParagraph.classList.add('az-video-paused');
- parentParagraph.classList.remove('az-video-playing');
- };
- }
-
// Helper function to initialize a single Vimeo element
function initVimeoElement(element, defaultOptions) {
const parentParagraph = element.parentNode;
@@ -111,23 +91,33 @@
parentParagraph.classList.add('az-video-playing');
});
- // Play Button
- const playButtons = element.getElementsByClassName('az-video-play');
- if (playButtons[0]) {
- playButtons[0].addEventListener(
- 'click',
- handlePlayButtonClick(element, parentParagraph),
- );
- }
+ // Set the iframe tabindex to -1 to prevent focus from reaching iframe.
+ element.player.ready().then(() => {
+ const iframe = element.player.element;
+ if (iframe) {
+ iframe.setAttribute('tabindex', '-1');
+ }
+ });
- // Pause Button
- const pauseButtons = element.getElementsByClassName('az-video-pause');
- if (pauseButtons[0]) {
- pauseButtons[0].addEventListener(
- 'click',
- handlePauseButtonClick(element, parentParagraph),
- );
- }
+ // Play/Pause button toggle.
+ const playPauseButton =
+ element.getElementsByClassName('az-video-playpause')[0];
+ playPauseButton.addEventListener('click', (event) => {
+ event.preventDefault();
+ if (event.currentTarget.textContent === 'Play Video') {
+ element.player.play().catch((error) => vimeoError(error));
+ parentParagraph.classList.remove('az-video-paused');
+ parentParagraph.classList.add('az-video-playing');
+ event.currentTarget.textContent = 'Pause Video';
+ event.currentTarget.setAttribute('title', 'Pause the video');
+ } else {
+ element.player.pause().catch((error) => vimeoError(error));
+ parentParagraph.classList.remove('az-video-playing');
+ parentParagraph.classList.add('az-video-paused');
+ event.currentTarget.textContent = 'Play Video';
+ event.currentTarget.setAttribute('title', 'Play the video');
+ }
+ });
}
// Helper function to handle API loaded callback
diff --git a/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_youtube.js b/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_youtube.js
index bacdd26ca1..035e836106 100644
--- a/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_youtube.js
+++ b/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_youtube.js
@@ -54,21 +54,25 @@
onStateChange: window.onPlayerStateChange,
},
});
- const playButton =
- element.getElementsByClassName('az-video-play')[0];
- playButton.addEventListener('click', (event) => {
- event.preventDefault();
- element.player.playVideo();
- parentParagraph.classList.remove('az-video-paused');
- parentParagraph.classList.add('az-video-playing');
- });
- const pauseButton =
- element.getElementsByClassName('az-video-pause')[0];
- pauseButton.addEventListener('click', (event) => {
+
+ // Play/Pause button toggle.
+ const playPauseButton =
+ element.getElementsByClassName('az-video-playpause')[0];
+ playPauseButton.addEventListener('click', (event) => {
event.preventDefault();
- element.player.pauseVideo();
- parentParagraph.classList.remove('az-video-playing');
- parentParagraph.classList.add('az-video-paused');
+ if (event.currentTarget.textContent === 'Play Video') {
+ element.player.playVideo();
+ parentParagraph.classList.remove('az-video-paused');
+ parentParagraph.classList.add('az-video-playing');
+ event.currentTarget.textContent = 'Pause Video';
+ event.currentTarget.setAttribute('title', 'Pause the video');
+ } else {
+ element.player.pauseVideo();
+ parentParagraph.classList.remove('az-video-playing');
+ parentParagraph.classList.add('az-video-paused');
+ event.currentTarget.textContent = 'Play Video';
+ event.currentTarget.setAttribute('title', 'Play the video');
+ }
});
});
};
@@ -119,6 +123,10 @@
};
window.onPlayerReady = (event) => {
+ // Set the iframe tabindex to -1 to prevent focus from reaching iframe.
+ const iframe = event.target.getIframe();
+ iframe.setAttribute('tabindex', '-1');
+
const id = event.target.options.videoId;
if (!bgVideoSettings[id].autoplay) {
return;
diff --git a/modules/custom/az_paragraphs/az_paragraphs_text_media/templates/media--az-remote-video--az-background.html.twig b/modules/custom/az_paragraphs/az_paragraphs_text_media/templates/media--az-remote-video--az-background.html.twig
index 9588142c1a..dfdc5b0e97 100644
--- a/modules/custom/az_paragraphs/az_paragraphs_text_media/templates/media--az-remote-video--az-background.html.twig
+++ b/modules/custom/az_paragraphs/az_paragraphs_text_media/templates/media--az-remote-video--az-background.html.twig
@@ -13,5 +13,4 @@
-Pause Video
-Play Video
+
diff --git a/modules/custom/az_paragraphs/css/az_paragraphs_az_text_media.css b/modules/custom/az_paragraphs/css/az_paragraphs_az_text_media.css
index 17698d1155..646157d1be 100644
--- a/modules/custom/az_paragraphs/css/az_paragraphs_az_text_media.css
+++ b/modules/custom/az_paragraphs/css/az_paragraphs_az_text_media.css
@@ -49,7 +49,6 @@
right: 0;
font-size: 0.9em;
color: #0c234b;
- z-index: -102;
cursor: pointer;
padding: 0.3em 0.6em;
border: none;
@@ -60,12 +59,6 @@
color: #ab0520;
border-color: #ab0520;
}
-.az-video-playing .az-video-pause {
- z-index: 2;
-}
-.az-video-paused .az-video-play {
- z-index: 2;
-}
.az-video-container iframe {
position: absolute;
}
From 691c1e8d83a6e6e30abfd499f3695777cac06374 Mon Sep 17 00:00:00 2001
From: Jeff Bishop
Date: Tue, 5 May 2026 12:01:24 -0700
Subject: [PATCH 2/2] =?UTF-8?q?a11y:=20video=20play/pause=20button=20?=
=?UTF-8?q?=E2=80=94=20aria-pressed,=20event-driven=20state,=20fix=20aria-?=
=?UTF-8?q?hidden=20(closes=20#5515)=20(#5516)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* a11y: video button aria-pressed state, event-driven sync, fix aria-hidden
Closes #5515
- Remove aria-hidden="" from button (was hiding it from AT)
- Remove redundant title attribute (visible text content is sufficient)
- Set aria-pressed="true" as initial default (conservative: video not
confirmed playing until player fires its play event)
- Change button initial label to "Play Video" (matches aria-pressed state)
Vimeo:
- Replace textContent comparison in click handler with aria-pressed check
- Replace bufferend class management with dedicated play/pause events
- play event: sets "Pause Video" + aria-pressed="false" + classes
- pause event: sets "Play Video" + aria-pressed="true" + classes
- Click handler: only calls play()/pause(); events drive all state
YouTube:
- Replace textContent comparison in click handler with aria-pressed check
- onPlayerStateChange state 1: syncs button to "Pause Video" + aria-pressed="false"
- onPlayerStateChange state 2: syncs button to "Play Video" + aria-pressed="true"
- Both cases also manage az-video-playing/az-video-paused classes
* fix(lint): fix prettier line-break in vimeo.js (closes CI eslint failure)
Revert the split template literal at L48 back to a single line as
required by prettier. The line is within the 80-char print-width limit
so no wrap is needed.
* fix(lint): fix prettier and no-unused-vars errors in youtube.js
- Revert split `if (window.screen && ...)` back to one line (L5)
- Revert split `const firstScriptTag` back to one line (L20)
- Remove unused `parentParagraph` variable (L31): class state updates
were moved to onPlayerStateChange; the click handler no longer needs
to reference the parent container directly
- Wrap long `getAttribute('aria-pressed')` condition per prettier
print-width rules (L65)
* fix(a11y): address 7 Copilot review comments on video play/pause button
- template: fix initial aria-pressed from 'true' to 'false' (video not yet playing on load)
- youtube.js: invert click handler so aria-pressed='true' (playing) calls pauseVideo()
- youtube.js: add classList.remove('az-video-paused') when entering playing state
- youtube.js: set aria-pressed='true' in playing state, 'false' in paused state
- vimeo.js: set aria-pressed='true' in play event, 'false' in pause event
- vimeo.js: invert click handler so aria-pressed='true' (playing) calls pause()
All changes align aria-pressed semantics: true = video is playing,
false = video is not playing, matching the ARIA toggle button pattern.
Addresses Copilot review on #5516.
---
.../js/az_paragraphs_az_text_media_vimeo.js | 40 +++++++++++--------
.../js/az_paragraphs_az_text_media_youtube.js | 39 +++++++++++-------
...--az-remote-video--az-background.html.twig | 2 +-
3 files changed, 49 insertions(+), 32 deletions(-)
diff --git a/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_vimeo.js b/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_vimeo.js
index c653f8b152..e36237108b 100644
--- a/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_vimeo.js
+++ b/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_vimeo.js
@@ -85,10 +85,29 @@
muted: defaultOptions.muted,
});
- // Event listener for starting play.
+ // Play/Pause button reference used by event handlers below.
+ const playPauseButton =
+ element.getElementsByClassName('az-video-playpause')[0];
+
+ // Update dimensions when buffering completes.
element.player.on('bufferend', () => {
setDimensions(element);
+ });
+
+ // Sync button and class state when video plays.
+ element.player.on('play', () => {
+ parentParagraph.classList.remove('az-video-paused');
parentParagraph.classList.add('az-video-playing');
+ playPauseButton.textContent = 'Pause Video';
+ playPauseButton.setAttribute('aria-pressed', 'true');
+ });
+
+ // Sync button and class state when video pauses.
+ element.player.on('pause', () => {
+ parentParagraph.classList.remove('az-video-playing');
+ parentParagraph.classList.add('az-video-paused');
+ playPauseButton.textContent = 'Play Video';
+ playPauseButton.setAttribute('aria-pressed', 'false');
});
// Set the iframe tabindex to -1 to prevent focus from reaching iframe.
@@ -99,23 +118,13 @@
}
});
- // Play/Pause button toggle.
- const playPauseButton =
- element.getElementsByClassName('az-video-playpause')[0];
+ // Play/Pause button: delegate state changes to player events.
playPauseButton.addEventListener('click', (event) => {
event.preventDefault();
- if (event.currentTarget.textContent === 'Play Video') {
- element.player.play().catch((error) => vimeoError(error));
- parentParagraph.classList.remove('az-video-paused');
- parentParagraph.classList.add('az-video-playing');
- event.currentTarget.textContent = 'Pause Video';
- event.currentTarget.setAttribute('title', 'Pause the video');
- } else {
+ if (event.currentTarget.getAttribute('aria-pressed') === 'true') {
element.player.pause().catch((error) => vimeoError(error));
- parentParagraph.classList.remove('az-video-playing');
- parentParagraph.classList.add('az-video-paused');
- event.currentTarget.textContent = 'Play Video';
- event.currentTarget.setAttribute('title', 'Play the video');
+ } else {
+ element.player.play().catch((error) => vimeoError(error));
}
});
}
@@ -165,7 +174,6 @@
});
}
}
-
once('vimeoTextOnMedia-init', 'body').forEach(initVimeoBackgrounds);
},
};
diff --git a/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_youtube.js b/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_youtube.js
index 035e836106..094aa0b3a0 100644
--- a/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_youtube.js
+++ b/modules/custom/az_paragraphs/az_paragraphs_text_media/js/az_paragraphs_az_text_media_youtube.js
@@ -26,9 +26,6 @@
);
window.onYouTubeIframeAPIReady = () => {
Array.from(bgVideoParagraphs).forEach((element) => {
- const parentParagraph = document.getElementById(
- element.dataset.parentid,
- );
const youtubeId = element.dataset.youtubeid;
bgVideoSettings[youtubeId] = {
autoplay: element.dataset.autoplay === 'true',
@@ -55,23 +52,17 @@
},
});
- // Play/Pause button toggle.
+ // Play/Pause button: delegate state changes to player events.
const playPauseButton =
element.getElementsByClassName('az-video-playpause')[0];
playPauseButton.addEventListener('click', (event) => {
event.preventDefault();
- if (event.currentTarget.textContent === 'Play Video') {
- element.player.playVideo();
- parentParagraph.classList.remove('az-video-paused');
- parentParagraph.classList.add('az-video-playing');
- event.currentTarget.textContent = 'Pause Video';
- event.currentTarget.setAttribute('title', 'Pause the video');
- } else {
+ if (
+ event.currentTarget.getAttribute('aria-pressed') === 'true'
+ ) {
element.player.pauseVideo();
- parentParagraph.classList.remove('az-video-playing');
- parentParagraph.classList.add('az-video-paused');
- event.currentTarget.textContent = 'Play Video';
- event.currentTarget.setAttribute('title', 'Play the video');
+ } else {
+ element.player.playVideo();
}
});
});
@@ -134,6 +125,7 @@
if (defaultSettings.mute) {
event.target.mute();
}
+
event.target.seekTo(bgVideoSettings[id].start);
event.target.playVideo();
// Create and dispatch a new event when video starts playing.
@@ -155,7 +147,24 @@
if (event.data === 1) {
resize();
parentContainer.classList.add('az-video-playing');
+ parentContainer.classList.remove('az-video-paused');
parentContainer.classList.remove('az-video-loading');
+ // Sync button state: video is confirmed playing.
+ const btn = parentContainer.querySelector('.az-video-playpause');
+ if (btn) {
+ btn.textContent = 'Pause Video';
+ btn.setAttribute('aria-pressed', 'true');
+ }
+ }
+ if (event.data === 2) {
+ // Video paused: sync button state.
+ parentContainer.classList.remove('az-video-playing');
+ parentContainer.classList.add('az-video-paused');
+ const btn = parentContainer.querySelector('.az-video-playpause');
+ if (btn) {
+ btn.textContent = 'Play Video';
+ btn.setAttribute('aria-pressed', 'false');
+ }
}
};
diff --git a/modules/custom/az_paragraphs/az_paragraphs_text_media/templates/media--az-remote-video--az-background.html.twig b/modules/custom/az_paragraphs/az_paragraphs_text_media/templates/media--az-remote-video--az-background.html.twig
index dfdc5b0e97..14372f8a28 100644
--- a/modules/custom/az_paragraphs/az_paragraphs_text_media/templates/media--az-remote-video--az-background.html.twig
+++ b/modules/custom/az_paragraphs/az_paragraphs_text_media/templates/media--az-remote-video--az-background.html.twig
@@ -13,4 +13,4 @@
-
+