Skip to content

fix(react): prevent gesture tap from firing on slider interactions#1361

Merged
mihar-22 merged 4 commits intomainfrom
t3code/37ff898d
Apr 18, 2026
Merged

fix(react): prevent gesture tap from firing on slider interactions#1361
mihar-22 merged 4 commits intomainfrom
t3code/37ff898d

Conversation

@mihar-22
Copy link
Copy Markdown
Member

@mihar-22 mihar-22 commented Apr 18, 2026

Summary

  • Move stopPropagation() before the early return guard in the slider's onPointerUp handler so pointer events always stop propagating to parent gesture coordinators, even when no pointer was captured
  • Add [data-interactive] to INTERACTIVE_SELECTOR so any element can opt into gesture filtering via a data attribute — workaround for React's synthetic stopPropagation not blocking native events in time

Test plan

  • Tap on slider in React player — should not trigger parent gesture (e.g., togglePaused)
  • Doubletap on slider regions — should not trigger seek/fullscreen gestures
  • Normal slider drag interaction still works
  • Tap on non-interactive areas still fires gestures correctly
  • pnpm typecheck passes
  • pnpm test passes

🤖 Generated with Claude Code


Note

Medium Risk
Changes pointer-event propagation and gesture filtering around sliders, which can subtly affect click/tap behavior across players. Risk is moderate due to cross-cutting input/gesture handling, but the logic change is small and covered by new e2e tests.

Overview
Prevents slider taps/clicks from leaking to parent gesture coordinators by ensuring the slider’s onPointerUp always calls stopPropagation() (even when no pointer capture occurred) and by bailing early when disabled.

Extends gesture-interactive filtering to allow any element to opt-in via [data-interactive], and adds Playwright coverage (HTML and React players) asserting slider clicks seek without triggering container tap gestures.

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

React's synthetic `stopPropagation` doesn't prevent native pointer events
from reaching the gesture coordinator in time. Two fixes:

1. Move `stopPropagation()` before the `capturedPointerId` guard in the
   slider's `onPointerUp` so it always blocks propagation, even when no
   pointer was captured.

2. Add `[data-interactive]` to the interactive selector so any element
   can opt into gesture filtering via a data attribute.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 18, 2026

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

Project Deployment Actions Updated (UTC)
v10-sandbox Ready Ready Preview, Comment Apr 18, 2026 0:48am

Request Review

@netlify
Copy link
Copy Markdown

netlify bot commented Apr 18, 2026

Deploy Preview for vjs10-site ready!

Name Link
🔨 Latest commit 65bb36b
🔍 Latest deploy log https://app.netlify.com/projects/vjs10-site/deploys/69e2d4c37f888d0008329c57
😎 Deploy Preview https://deploy-preview-1361--vjs10-site.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

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

@mihar-22 mihar-22 changed the title fix(packages): prevent gesture tap from firing on slider interactions fix(react): prevent gesture tap from firing on slider interactions Apr 18, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 18, 2026

📦 Bundle Size Report

🎨 @videojs/html — no changes
Presets (7)
Entry Size
/video (default) 28.45 kB
/video (default + hls) 160.62 kB
/video (minimal) 25.98 kB
/video (minimal + hls) 158.15 kB
/audio (default) 26.36 kB
/audio (minimal) 23.95 kB
/background 4.15 kB
Media (8)
Entry Size
/media/background-video 1.04 kB
/media/container 1.73 kB
/media/dash-video 236.43 kB
/media/hls-video 133.51 kB
/media/mux-audio 159.50 kB
/media/mux-video 159.58 kB
/media/native-hls-video 3.50 kB
/media/simple-hls-video 15.78 kB
Players (3)
Entry Size
/video/player 6.98 kB
/audio/player 5.06 kB
/background/player 3.86 kB
Skins (17)
Entry Type Size
/video/minimal-skin.css css 3.50 kB
/video/skin.css css 3.52 kB
/video/minimal-skin js 25.95 kB
/video/minimal-skin.tailwind js 26.17 kB
/video/skin js 28.50 kB
/video/skin.tailwind js 28.56 kB
/audio/minimal-skin.css css 2.53 kB
/audio/skin.css css 2.50 kB
/audio/minimal-skin js 23.95 kB
/audio/minimal-skin.tailwind js 24.13 kB
/audio/skin js 26.35 kB
/audio/skin.tailwind js 26.51 kB
/background/skin.css css 117 B
/background/skin js 1.14 kB
/base.css css 157 B
/shared.css css 88 B
/skin-element js 1.35 kB
UI Components (25)
Entry Size
/ui/alert-dialog 981 B
/ui/alert-dialog-close 429 B
/ui/alert-dialog-description 375 B
/ui/alert-dialog-title 353 B
/ui/buffering-indicator 2.24 kB
/ui/captions-button 2.55 kB
/ui/cast-button 2.49 kB
/ui/compounds 3.89 kB
/ui/controls 2.19 kB
/ui/error-dialog 2.90 kB
/ui/fullscreen-button 2.54 kB
/ui/hotkey 2.53 kB
/ui/mute-button 2.51 kB
/ui/pip-button 2.52 kB
/ui/play-button 2.55 kB
/ui/playback-rate-button 2.54 kB
/ui/popover 1.77 kB
/ui/poster 2.05 kB
/ui/seek-button 2.54 kB
/ui/slider 1.44 kB
/ui/thumbnail 2.59 kB
/ui/time 2.41 kB
/ui/time-slider 3.84 kB
/ui/tooltip 1.99 kB
/ui/volume-slider 3.22 kB

Sizes are marginal over the root entry point.

⚛️ @videojs/react — no changes
Presets (7)
Entry Size
/video (default) 23.28 kB
/video (default + hls) 154.28 kB
/video (minimal) 20.90 kB
/video (minimal + hls) 151.97 kB
/audio (default) 18.85 kB
/audio (minimal) 17.38 kB
/background 755 B
Media (7)
Entry Size
/media/background-video 575 B
/media/dash-video 234.89 kB
/media/hls-video 132.03 kB
/media/mux-audio 158.16 kB
/media/mux-video 158.04 kB
/media/native-hls-video 2.06 kB
/media/simple-hls-video 14.42 kB
Skins (14)
Entry Type Size
/video/minimal-skin.css css 3.43 kB
/video/skin.css css 3.45 kB
/video/minimal-skin js 20.80 kB
/video/minimal-skin.tailwind js 24.29 kB
/video/skin js 23.17 kB
/video/skin.tailwind js 24.41 kB
/audio/minimal-skin.css css 2.43 kB
/audio/skin.css css 2.39 kB
/audio/minimal-skin js 17.30 kB
/audio/minimal-skin.tailwind js 19.79 kB
/audio/skin js 18.77 kB
/audio/skin.tailwind js 19.80 kB
/background/skin.css css 90 B
/background/skin js 272 B
UI Components (20)
Entry Size
/ui/alert-dialog 1.13 kB
/ui/buffering-indicator 1.28 kB
/ui/captions-button 1.94 kB
/ui/cast-button 1.96 kB
/ui/controls 1.33 kB
/ui/error-dialog 1.77 kB
/ui/fullscreen-button 1.94 kB
/ui/mute-button 1.96 kB
/ui/pip-button 1.94 kB
/ui/play-button 1.92 kB
/ui/playback-rate-button 1.97 kB
/ui/popover 1.89 kB
/ui/poster 1.21 kB
/ui/seek-button 1.96 kB
/ui/slider 2.63 kB
/ui/thumbnail 1.54 kB
/ui/time 2.06 kB
/ui/time-slider 2.19 kB
/ui/tooltip 2.28 kB
/ui/volume-slider 2.26 kB

Sizes are marginal over the root entry point.

🧩 @videojs/core — no changes
Entries (9)
Entry Size
. 4.89 kB
/dom 11.62 kB
/dom/media/castable 4.05 kB
/dom/media/custom-media-element 1.90 kB
/dom/media/dash 234.24 kB
/dom/media/hls 131.37 kB
/dom/media/mux 157.47 kB
/dom/media/native-hls 1.32 kB
/dom/media/simple-hls 13.73 kB
🏷️ @videojs/element — no changes
Entries (2)
Entry Size
. 999 B
/context 943 B
📦 @videojs/store — no changes
Entries (3)
Entry Size
. 1.39 kB
/html 695 B
/react 360 B
🔧 @videojs/utils — no changes
Entries (10)
Entry Size
/array 104 B
/dom 1.92 kB
/events 319 B
/function 327 B
/object 275 B
/predicate 265 B
/string 148 B
/style 190 B
/time 478 B
/number 158 B
📦 @videojs/spf — no changes
Entries (3)
Entry Size
. 40 B
/dom 13.30 kB
/playback-engine 13.17 kB

ℹ️ How to interpret

All sizes are standalone totals (minified + brotli).

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

Run pnpm size locally to check current sizes.

…erer

Add e2e tests verifying that clicking a slider does not trigger the
parent container gesture (togglePaused). Also adds a React-specific
gesture test suite to catch synthetic event propagation issues.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c8a78fc. Configure here.

Comment thread packages/core/src/dom/ui/slider.ts
Replace 5s polling timeout with a short wait + instant check so the
test fails fast when a gesture leaks through instead of timing out.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Match the onPointerDown guard — disabled sliders should let events
propagate so parent gesture coordinators and activity tracking work.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mihar-22 mihar-22 merged commit 769d436 into main Apr 18, 2026
27 checks passed
@mihar-22 mihar-22 deleted the t3code/37ff898d branch April 18, 2026 01:01
@luwes luwes mentioned this pull request Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant