Repository navigation
Let keyboard users reach the native controls of audio and video players in an activity - #5891
Merged
Merged
Conversation
Collaborator
Author
|
TODO: let's add snapshots and use dark-green video. |
Collaborator
Author
|
2 of 11 tasks
added 4 commits
October 17, 2026 18:15
…tivity The activity focus trap counted `<audio controls>` and `<video controls>` as one element and cancelled TAB on it, so the player's own controls (play, time scrubber, volume, mute, more options) were unreachable with the keyboard. Regression from #5243, which replaced the trap's sentinels with key handling. These controls are in a closed shadow tree: they cannot be focused from script and their keystrokes do not reach the page. TAB on a media element is no longer cancelled, a guard at the end of the trap body wraps the focus after the player's last control, and SHIFT+TAB on the first element continues from the guard into the player's last control. Fixes #5738, fixes #5709.
…title The <audio> and <video> of audio and video cards had no accessible name. They now pass the card title as `alt` (rendered as `aria-label`), like attachments pass the attachment name. The animation card keeps `profile` and falls back to the title for its video player.
…eo in tests - Snapshot the focus indicator of the native controls of the audio player (default and Fluent), the audio card, the video attachment, and the video card. - Use a uniform dark green test video, so the video is distinguishable from the black gradient behind the player controls.
Eugene (OEvgeny)
marked this pull request as ready for review
October 18, 2026 01:17
Eugene (OEvgeny)
requested review from
Chris Whitten (cwhitten) and
TJ Durnford (tdurnford)
as code owners
October 18, 2026 01:17
Make the focus trap tests of audio, video, and the media cards consistent: - Take a snapshot after ENTER and after every TAB and SHIFT+TAB. - Go through every control of the player and wrap around in both directions: TAB from the last control wraps to the player, and SHIFT+TAB from the player wraps to the last control. - Add snapshots to the animation card test, now that #5887 is merged.
Eugene (OEvgeny)
force-pushed
the
OEvgeny/fix-5738-audio-keyboard-access
branch
from
October 18, 2026 01:34
c78009d to
3a32429
Compare
William Wong (compulim)
approved these changes
Oct 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Changelog Entry
Fixed
Description
This is a regression from #5243 (4.19.0). In 4.18.0, TAB moves through the controls of an audio player in an activity. SHIFT + TAB on the player stayed on it, even in 4.18.0. This change fixes both.
After pressing ENTER on an activity with an audio attachment or an audio card, the focus is on the
<audio>element. TAB and SHIFT + TAB then kept it there. The player's own controls (play, time scrubber, volume, mute, more options) could not be reached, so mute, playback speed, and download could not be used with the keyboard. On a plain page, Edge moves through all of these controls. The activity focus trap counts the player as one element and cancelled TAB on it. #5243 replaced the focus sentinels of the trap with key handling, and the end sentinel was what used to catch TAB after the player's last control.The trap now lets the browser move through the player's controls and wraps the focus after the last one. Video attachments (
<video controls>) had the same problem and are fixed too.The players of audio and video cards (and of animation cards without
profile), which keyboard users can now reach, had no accessible name: they are now named after the card title, as the players of attachments are named after the attachment name.#5739 and #5741 (name and role of the play/pause control) should be re-tested after this change. They were reported on the
<audio>element itself (read as "BotFramework Test, audio"), which was the only element the trap let the keyboard reach. The player's play button (role button, name "play" or "pause") is now reachable.Design
<audio controls>and<video controls>are in a closed shadow tree. Web Chat cannot list or focus them, anddocument.activeElementis the media element for all of them. Their keystrokes also do not reach the page: in Edge there is nokeydownondocumentfrom these controls, not even in the capture phase. So the trap cannot see when TAB leaves the last control.<iframe>(see follow-ups). TAB on other elements is still handled by the existing key handling.aria-hidden, because axe flags focusable content insidearia-hidden. It is an empty<div>, exposed likeFocusRedirector(generic, no name).<audio>or<video>element itself, one TAB or SHIFT + TAB away.__tests__/assets/dark-green-video.webm, a uniform dark green video (2 seconds, no audio track), so the video stands out from the black gradient behind the player controls.<video>element by the element itself, also on a plain page.altprop (aria-label) that attachments fill with the attachment name. Without a title, the player has noaria-label, as before. Theprofileof the media is not used for these cards, because bots send it as a hint to tell media apart (the mock bot sendsaudiocard), not as a label.profile; this is unchanged. Withoutprofile, its video player now falls back to the card title. Its GIF image withoutprofilekeepsalt=""(decorative), because it is not a control.<iframe>, instead of "A video clip", the same as a video attachment with a name.<iframe>(YouTube or Vimeo video cards) has the same invisible keystrokes. TAB out of it now wraps through the guard, but SHIFT + TAB out of an<iframe>that is the first element still leaves the activity. Not tested.Specific Changes
Transcript/FocusTrap.tsx:Added
testHelpers.getFocusedAccessibilityNode(), which returns the focused node of the accessibility tree via Chrome DevTools Protocol. Unlikedocument.activeElement, it also sees the focus inside the player's controls.AudioCardContent.tsxandVideoCardContent.tsx: the player is named after the card title.AnimationCardContent.tsx: the video player falls back to the card title when the media has noprofile.Added
__tests__/html2/transcript/navigation/focusTrap.audio.html(with a.fluent.htmlvariant),focusTrap.audioCard.html,focusTrap.video.html,focusTrap.videoCard.html, andfocusTrap.animationCard.html. They enter the activity with the keyboard, TAB and SHIFT + TAB through the player's controls, and check where the focus is and the name of the player.Added
__tests__/assets/dark-green-video.webmfor the video tests.I have added tests and executed them locally
I have updated
CHANGELOG.mdI have updated documentation
Review Checklist
z-index)package.jsonandpackage-lock.jsonreviewed