From b0d76cf0c17726feeb3d8743b6f943aeebe893c2 Mon Sep 17 00:00:00 2001 From: Brad Simpson Date: Tue, 4 Aug 2026 10:35:53 -0600 Subject: [PATCH] Fix: reveal captions, chapters and speed menus while they have focus --- less/mep-overrides.less | 32 ++++++++++++++++++++++++++++++++ less/plugin-overrides.less | 28 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/less/mep-overrides.less b/less/mep-overrides.less index 324d64d4..1e2b948f 100644 --- a/less/mep-overrides.less +++ b/less/mep-overrides.less @@ -26,3 +26,35 @@ .mejs__button.mejs__jump-forward-button > button { background-size: contain; } + +// Keyboard visibility of the captions and chapters menus +// -------------------------------------------------- +// MediaElement leaves the visually-hidden `.mejs__offscreen` class applied to +// these menus while they hold focus, so a keyboard user tabs into a live list +// of radios and arrows through options with nothing visible on screen. +// Reveal the menu whenever focus is anywhere inside its button, mirroring the +// existing hover behaviour. +// Upstream: https://github.com/mediaelement/mediaelement/issues/2949 +// `.mejs__captions-button-toggle` is excluded because in that mode the button +// is a plain on/off toggle: MediaElement still builds the list but binds no +// handlers to it, so revealing it would surface an inert menu. +.mejs__captions-button:not(.mejs__captions-button-toggle):focus-within > .mejs__captions-selector, +.mejs__chapters-button:focus-within > .mejs__chapters-selector { + // Undo `.mejs__offscreen` only. Width, border, overflow and the negative + // right margin that centres the menu all come from the more specific + // `.mejs__captions-button > .mejs__captions-selector` rule and still apply. + clip: auto; + clip-path: none; + height: auto; + margin-top: 0; + margin-bottom: 0; + margin-left: 0; +} + +// The radio inputs sit off screen so that only their labels show, which leaves +// the focused option with no visible focus indicator once the menu is revealed. +.mejs__captions-selector-list-item:has(:focus-visible), +.mejs__chapters-selector-list-item:has(:focus-visible) { + outline: 0.125rem solid @white; + outline-offset: -0.125rem; +} diff --git a/less/plugin-overrides.less b/less/plugin-overrides.less index cfe2952a..25944bb7 100644 --- a/less/plugin-overrides.less +++ b/less/plugin-overrides.less @@ -21,3 +21,31 @@ line-height: normal; position: relative; } + +// Speed +// Keyboard visibility of the speed menu +// https://github.com/mediaelement/mediaelement-plugins/tree/master/src/speed +// -------------------------------------------------- +// The menu is only revealed on hover, and `visibility: hidden` also makes its +// radios unfocusable, so keyboard users cannot reach the speed options at all. +// MediaElement does remove the visually-hidden `.mejs__offscreen` class on +// focus, but that alone leaves the menu hidden. Reveal it whenever focus is +// anywhere inside the button, mirroring the existing hover behaviour. +// Upstream: https://github.com/mediaelement/mediaelement/issues/2949 +.mejs__speed-button:focus-within > .mejs__speed-selector, +.mejs-speed-button:focus-within > .mejs-speed-selector { + visibility: visible; + clip: auto; + clip-path: none; + margin: 0; +} + +// The radio inputs sit off screen so that only their labels show, which leaves +// the focused option with no visible focus indicator once the menu is revealed. +// The outline goes on the list item rather than the label because the label is +// wider than the menu, so an outline on it would be clipped on the right. +.mejs__speed-selector-list-item:has(:focus-visible), +.mejs-speed-selector-list-item:has(:focus-visible) { + outline: 0.125rem solid @white; + outline-offset: -0.125rem; +}