Skip to content

fix(packages): prevent controls click triggering interactions - #1885

Merged
sampotts merged 1 commit into
mainfrom
fix/controls-click
Jul 30, 2026
Merged

fix(packages): prevent controls click triggering interactions#1885
sampotts merged 1 commit into
mainfrom
fix/controls-click

Conversation

@sampotts

@sampotts sampotts commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Add the data-interactive escape hatch the controls container, preventing clicks from triggering any click interactions bound to the main container.


Note

Low Risk
Small, targeted DOM attribute change with tests; affects gesture hit-testing only, not playback or auth.

Overview
Clicks on the controls bar (not just individual buttons or sliders) were still bubbling into the player’s container tap gesture and could toggle play/pause. This PR marks the whole controls root as an interactive surface so those pointer events are ignored by container gestures.

HTML ControlsElement sets data-interactive in connectedCallback. React ControlsRoot passes the same attribute on its root div. Unit tests cover both implementations, core gesture behavior for descendants inside a data-interactive ancestor, and e2e tests for HTML and React verify pointer events on the controls container do not change playback state.

Reviewed by Cursor Bugbot for commit d3be0a2. Bugbot is set up for automated code reviews on this repo. Configure here.

@netlify

netlify Bot commented Jul 29, 2026

Copy link
Copy Markdown

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit d3be0a2
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/6a6a922d620f310008e8ceb8
😎 Deploy Preview https://deploy-preview-1885--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v10-sandbox Ready Ready Preview Jul 29, 2026 11:52pm

Request Review

@sampotts
sampotts requested review from cjpillsbury and mihar-22 July 29, 2026 23:52
@github-actions

Copy link
Copy Markdown
Contributor

📦 Bundle Size Report

🎨 @videojs/html — no changes
Presets (7)
Entry Initial Lazy
/video (default) 52.39 kB 50.16 kB
/video (default + hls) 191.83 kB 50.16 kB
/video (minimal) 52.26 kB 50.16 kB
/video (minimal + hls) 191.65 kB 50.16 kB
/audio (default) 45.42 kB 50.16 kB
/audio (minimal) 41.99 kB 50.16 kB
/background 4.20 kB
Media (10)
Entry Initial
/media/background-video 1.14 kB
/media/container 1.71 kB
/media/dash-video 214.86 kB
/media/hlsjs-video 141.54 kB
/media/mux-audio 164.86 kB
/media/mux-video 164.86 kB
/media/native-hls-video 9.07 kB
/media/simple-hls-audio-only 19.08 kB
/media/simple-hls-video 21.13 kB
/media/vimeo-video 12.31 kB
Players (5)
Entry Initial
/video/player 8.22 kB
/audio/player 5.37 kB
/background/player 3.92 kB
/live-video/player 7.63 kB
/live-audio/player 5.38 kB
Skins (30)
Entry Type Initial Lazy
/video/minimal-skin.css css 5.70 kB
/video/skin.css css 5.66 kB
/video/minimal-skin js 52.33 kB 50.16 kB
/video/minimal-skin.tailwind js 53.00 kB 50.16 kB
/video/skin js 52.40 kB 50.16 kB
/video/skin.tailwind js 53.18 kB 50.16 kB
/audio/minimal-skin.css css 3.97 kB
/audio/skin.css css 3.86 kB
/audio/minimal-skin js 41.99 kB 50.16 kB
/audio/minimal-skin.tailwind js 42.49 kB 50.16 kB
/audio/skin js 45.45 kB 50.16 kB
/audio/skin.tailwind js 45.94 kB 50.16 kB
/background/skin.css css 133 B
/background/skin js 1.14 kB
/live-video/minimal-skin.css css 5.70 kB
/live-video/skin.css css 5.66 kB
/live-video/minimal-skin js 48.63 kB 50.16 kB
/live-video/minimal-skin.tailwind js 49.14 kB 50.16 kB
/live-video/skin js 50.85 kB 50.16 kB
/live-video/skin.tailwind js 51.49 kB 50.16 kB
/live-audio/minimal-skin.css css 3.97 kB
/live-audio/skin.css css 3.86 kB
/live-audio/minimal-skin js 34.17 kB 50.16 kB
/live-audio/minimal-skin.tailwind js 33.64 kB 50.16 kB
/live-audio/skin js 37.68 kB 50.16 kB
/live-audio/skin.tailwind js 37.26 kB 50.16 kB
/global.css css 183 B
/shared.css css 153 B
/tailwind.css css 161 B
/skin-element js 1.51 kB
UI Components (39)
Entry Initial
/ui/airplay-button 2.52 kB
/ui/alert-dialog 2.89 kB
/ui/alert-dialog-close 2.41 kB
/ui/alert-dialog-description 2.39 kB
/ui/alert-dialog-title 2.43 kB
/ui/audio-track-radio-group 2.97 kB
/ui/buffering-indicator 2.61 kB
/ui/captions-button 2.56 kB
/ui/captions-radio-group 2.98 kB
/ui/cast-button 2.54 kB
/ui/compounds 3.16 kB
/ui/controls 2.85 kB
/ui/error-dialog 2.87 kB
/ui/fullscreen-button 2.58 kB
/ui/hotkey 2.56 kB
/ui/menu 2.89 kB
/ui/mute-button 2.59 kB
/ui/pip-button 2.55 kB
/ui/play-button 2.56 kB
/ui/playback-rate-button 2.61 kB
/ui/playback-rate-radio-group 2.77 kB
/ui/popover 3.13 kB
/ui/poster 2.40 kB
/ui/quality-radio-group 2.92 kB
/ui/seek-button 2.46 kB
/ui/seek-indicator 2.83 kB
/ui/seek-indicator-value 386 B
/ui/slider 2.87 kB
/ui/status-announcer 2.42 kB
/ui/status-indicator 2.53 kB
/ui/status-indicator-value 421 B
/ui/thumbnail 2.60 kB
/ui/time 2.86 kB
/ui/time-slider 2.89 kB
/ui/tooltip 2.98 kB
/ui/volume-indicator 2.56 kB
/ui/volume-indicator-fill 407 B
/ui/volume-indicator-value 388 B
/ui/volume-slider 2.87 kB

Sizes are marginal over the root entry point.

⚛️ @videojs/react — no changes
Presets (7)
Entry Initial Lazy
/video (default) 41.51 kB 50.16 kB
/video (default + hls) 179.76 kB 50.16 kB
/video (minimal) 41.88 kB 50.16 kB
/video (minimal + hls) 179.91 kB 50.16 kB
/audio (default) 34.65 kB 50.16 kB
/audio (minimal) 34.71 kB 50.16 kB
/background 581 B
Media (9)
Entry Initial
/media/background-video 394 B
/media/dash-video 213.12 kB
/media/hlsjs-video 139.90 kB
/media/mux-audio 163.12 kB
/media/mux-video 163.36 kB
/media/native-hls-video 7.29 kB
/media/simple-hls-audio-only 17.39 kB
/media/simple-hls-video 19.42 kB
/media/vimeo-video 10.46 kB
Skins (27)
Entry Type Initial Lazy
/tailwind.css css 161 B
/video/minimal-skin.css css 5.56 kB
/video/skin.css css 5.52 kB
/video/minimal-skin js 41.82 kB 50.16 kB
/video/minimal-skin.tailwind js 47.84 kB 50.16 kB
/video/skin js 41.36 kB 50.16 kB
/video/skin.tailwind js 47.51 kB 50.16 kB
/audio/minimal-skin.css css 3.79 kB
/audio/skin.css css 3.68 kB
/audio/minimal-skin js 34.61 kB 50.16 kB
/audio/minimal-skin.tailwind js 36.63 kB 50.16 kB
/audio/skin js 34.54 kB 50.16 kB
/audio/skin.tailwind js 38.79 kB 50.16 kB
/background/skin.css css 90 B
/background/skin js 272 B
/live-video/minimal-skin.css css 5.56 kB
/live-video/skin.css css 5.52 kB
/live-video/minimal-skin js 36.12 kB 50.16 kB
/live-video/minimal-skin.tailwind js 41.97 kB 50.16 kB
/live-video/skin js 36.13 kB 50.16 kB
/live-video/skin.tailwind js 42.04 kB 50.16 kB
/live-audio/minimal-skin.css css 3.79 kB
/live-audio/skin.css css 3.68 kB
/live-audio/minimal-skin js 24.70 kB 50.16 kB
/live-audio/minimal-skin.tailwind js 27.76 kB 50.16 kB
/live-audio/skin js 24.73 kB 50.16 kB
/live-audio/skin.tailwind js 27.86 kB 50.16 kB
UI Components (33)
Entry Initial
/ui/airplay-button 2.50 kB
/ui/alert-dialog 2.70 kB
/ui/audio-track 2.39 kB
/ui/buffering-indicator 2.63 kB
/ui/captions-button 2.45 kB
/ui/captions-radio-group 2.34 kB
/ui/cast-button 2.52 kB
/ui/controls 2.53 kB
/ui/error-dialog 2.47 kB
/ui/fullscreen-button 2.55 kB
/ui/gesture 2.52 kB
/ui/hotkey 2.46 kB
/ui/live-button 2.38 kB
/ui/menu 2.67 kB
/ui/mute-button 2.53 kB
/ui/pip-button 2.55 kB
/ui/play-button 2.48 kB
/ui/playback-rate 2.46 kB
/ui/playback-rate-button 2.49 kB
/ui/popover 3.18 kB
/ui/poster 2.50 kB
/ui/quality 2.31 kB
/ui/seek-button 2.46 kB
/ui/seek-indicator 2.59 kB
/ui/slider 2.52 kB
/ui/status-announcer 2.38 kB
/ui/status-indicator 2.41 kB
/ui/thumbnail 2.54 kB
/ui/time 2.26 kB
/ui/time-slider 2.52 kB
/ui/tooltip 3.14 kB
/ui/volume-indicator 2.41 kB
/ui/volume-slider 2.63 kB

Sizes are marginal over the root entry point.

🧩 @videojs/core — no changes
Entries (72)
Entry Initial Lazy
. 10.79 kB
/dom 17.82 kB
/i18n 2.99 kB 50.16 kB
/i18n/locales/all 30.51 kB
/i18n/locales/ar 1.11 kB
/i18n/locales/az 1.01 kB
/i18n/locales/bg 1.17 kB
/i18n/locales/bn 1.20 kB
/i18n/locales/bs 926 B
/i18n/locales/ca 988 B
/i18n/locales/cs 978 B
/i18n/locales/cy 948 B
/i18n/locales/da 918 B
/i18n/locales/de 1023 B
/i18n/locales/el 1.37 kB
/i18n/locales/en 707 B
/i18n/locales/es 925 B
/i18n/locales/et 995 B
/i18n/locales/eu 939 B
/i18n/locales/fa 1.11 kB
/i18n/locales/fi 970 B
/i18n/locales/fr 1001 B
/i18n/locales/gd 1.00 kB
/i18n/locales/gl 929 B
/i18n/locales/he 1.03 kB
/i18n/locales/hi 1.21 kB
/i18n/locales/hr 948 B
/i18n/locales/hu 1019 B
/i18n/locales/it 958 B
/i18n/locales/ja 1.10 kB
/i18n/locales/ko 1.04 kB
/i18n/locales/lv 1012 B
/i18n/locales/mr 1.21 kB
/i18n/locales/nb 908 B
/i18n/locales/ne 1.20 kB
/i18n/locales/nl 934 B
/i18n/locales/nn 913 B
/i18n/locales/oc 999 B
/i18n/locales/pl 1.03 kB
/i18n/locales/pt 955 B
/i18n/locales/pt-BR 955 B
/i18n/locales/pt-PT 914 B
/i18n/locales/ro 996 B
/i18n/locales/ru 1.24 kB
/i18n/locales/sk 1018 B
/i18n/locales/sl 960 B
/i18n/locales/sr 989 B
/i18n/locales/sv 935 B
/i18n/locales/te 1.22 kB
/i18n/locales/th 1.19 kB
/i18n/locales/tr 1003 B
/i18n/locales/uk 1.27 kB
/i18n/locales/vi 1006 B
/i18n/locales/zh 947 B
/i18n/locales/zh-CN 947 B
/i18n/locales/zh-TW 949 B
/i18n/text/airplay 101 B
/i18n/text/buttons 137 B
/i18n/text/captions 93 B
/i18n/text/cast 114 B
/i18n/text/common 90 B
/i18n/text/errors 277 B
/i18n/text/fullscreen 98 B
/i18n/text/live 126 B
/i18n/text/menu 249 B
/i18n/text/pip 101 B
/i18n/text/playback 80 B
/i18n/text/seek 105 B
/i18n/text/slider 65 B
/i18n/text/status 179 B
/i18n/text/time 214 B
/i18n/text/volume 133 B
🏷️ @videojs/element — no changes
Entries (2)
Entry Initial
. 996 B
/context 943 B
📦 @videojs/store — no changes
Entries (3)
Entry Initial
. 1.39 kB
/html 696 B
/react 361 B
🔧 @videojs/utils — no changes
Entries (12)
Entry Initial
/array 104 B
/dom 2.94 kB
/events 319 B
/function 327 B
/jwt 176 B
/object 505 B
/predicate 265 B
/percent 281 B
/string 239 B
/style 190 B
/time 813 B
/number 158 B
📦 @videojs/media — no changes
Entries (14)
Entry Initial
. 959 B
/dom/audio-host 1.16 kB
/dom/custom-media-element 2.09 kB
/dom/dash 209.06 kB
/dom/google-cast 4.04 kB
/dom/hls-js 135.95 kB
/dom/media-host 1.27 kB
/dom/media-played-ranges 576 B
/dom/mux 159.27 kB
/dom/native-hls 3.06 kB
/dom/simple-hls 18.90 kB
/dom/simple-hls-audio-only 16.88 kB
/dom/video-host 1.44 kB
/dom/vimeo 9.88 kB
📦 @videojs/spf — no changes
Entries (4)
Entry Initial
. 4.46 kB
/dom 6.49 kB
/hls 17.85 kB
/background-video 13.30 kB

ℹ️ How to interpret

JS sizes are initial static graph totals (minified + brotli). Lazy dynamic chunks are shown separately when present.

Icon Meaning
No change
🔺 Increased ≤ 10%
🔴 Increased > 10%
🔽 Decreased
🆕 New (no baseline)

Run pnpm size locally to check current initial sizes.

@sampotts
sampotts enabled auto-merge (squash) July 30, 2026 01:12

@cjpillsbury cjpillsbury left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved with a couple of suggestions (one non-blocking/as a followup)

override connectedCallback(): void {
super.connectedCallback();

this.setAttribute('data-interactive', '');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought(non-blocking): this should not block merging/releasing imo, but, as a followup, we may want to consider another attribute or a different name, since this name is kind of "lying." These components aren't interactive. If anything, we're trying to identify them to disable a gesture-based interaction.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's more "contains interactive" since it tells the gesture logic to ignore interactions from this element but yeah, we can rename it.

stateAttrMap: ControlsDataAttrs,
ref: [forwardedRef],
props: [{ children }, elementProps],
props: [{ children }, elementProps, { 'data-interactive': '' }],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion(non-blocking): We may want to switch the order of elementProps and { 'data-interactive': '' } here so that folks could override the default (I think?)?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we want them to allow the interactions with the controls container to trigger gestures? I mean I guess we could 🤔

@sampotts
sampotts merged commit 0f4a9b4 into main Jul 30, 2026
27 checks passed
@sampotts
sampotts deleted the fix/controls-click branch July 30, 2026 14:37
@luwes luwes mentioned this pull request Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants