Skip to content

[all components] Fix synthetic event target regressions#4516

Merged
atomiks merged 9 commits intomui:masterfrom
atomiks:codex/scroll-area-hovering-target
Apr 6, 2026
Merged

[all components] Fix synthetic event target regressions#4516
atomiks merged 9 commits intomui:masterfrom
atomiks:codex/scroll-area-hovering-target

Conversation

@atomiks
Copy link
Copy Markdown
Contributor

@atomiks atomiks commented Apr 3, 2026

React's synthetic hover, pointer, and focus events can intentionally report a different event.target than the native event's composed-path leaf. These handlers need to keep using the synthetic target when they are making component-level active/inside checks.

Changes

  • Restore synthetic event.target checks for ScrollArea hover and scrollbar track interactions.
  • Restore synthetic event.target checks in hover and composite handlers that were switched to getTarget(event.nativeEvent).
  • Add regression coverage for cases where the synthetic target and native composed path intentionally differ.

@atomiks atomiks added component: scroll area Changes related to the scroll area component. type: bug It doesn't behave as expected. type: regression A bug, but worse, it used to behave as expected. labels Apr 3, 2026 — with ChatGPT Codex Connector
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 3, 2026

commit: 9f602bb

@mui-bot
Copy link
Copy Markdown

mui-bot commented Apr 3, 2026

Bundle size report

Bundle Parsed size Gzip size
@base-ui/react 🔺+41B(+0.01%) 🔺+17B(+0.01%)

Details of bundle changes


Check out the code infra dashboard for more information about this PR.

@netlify
Copy link
Copy Markdown

netlify bot commented Apr 3, 2026

Deploy Preview for base-ui ready!

Name Link
🔨 Latest commit 9f602bb
🔍 Latest deploy log https://app.netlify.com/projects/base-ui/deploys/69d37c5c5e293800089707f2
😎 Deploy Preview https://deploy-preview-4516--base-ui.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.

@atomiks atomiks added the internal Behind-the-scenes enhancement. Formerly called “core”. label Apr 3, 2026 — with ChatGPT Codex Connector
@atomiks atomiks changed the title [scroll area] Fix hovering attribute on pointer enter [all components] Fix synthetic event target regressions Apr 3, 2026
@atomiks atomiks marked this pull request as ready for review April 3, 2026 09:48
Copy link
Copy Markdown
Member

@flaviendelangle flaviendelangle left a comment

Choose a reason for hiding this comment

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

PR Review: [all components] Fix synthetic event target regressions

PR: #4516
Author: atomiks
Labels: type: bug, type: regression, component: scroll area, internal

Context

This PR reverts getTarget(event.nativeEvent) back to event.target in 4 source files. React's synthetic events intentionally normalize event.target to the React component boundary, which is correct for containment checks like contains(ref, target). Using getTarget(nativeEvent) bypasses this and can return a shadow DOM leaf or wrong element, breaking component-level hover/focus/click checks.

The fix is clean and consistent across all 4 locations. Import cleanup is done correctly in both ScrollArea files.


Critical Issues (1 found)

  • [test-analyzer] Missing test for ScrollAreaScrollbar.tsx thumb click change. The PR modifies the event.currentTarget !== event.target check (line 129) but no test covers this path. A test should render a ScrollArea with a visible thumb, dispatch a pointerdown on the thumb with a divergent composedPath, and verify the component still correctly distinguishes thumb clicks from track clicks.

Important Issues (1 found)

  • [code-reviewer] Possible unused getTarget import / nativeEvent destructuring in useHoverReferenceInteraction.ts and useHover.ts. The diff removes the only visible usage of getTarget(nativeEvent) in these handlers but doesn't show whether the import or destructuring is cleaned up. If getTarget/nativeEvent aren't used elsewhere in those files, they should be removed to avoid lint warnings.

Suggestions (2 found)

  • [test-analyzer] The useHover.test.tsx composedPath returns [document.body, child] which is an unrealistic ordering (body before child). While it doesn't affect correctness, a more realistic path like [child, button, document.body, ...] would avoid confusing future readers.
  • [test-analyzer] The CompositeRoot test asserts select-all behavior (selectionStart=0, selectionEnd=4) which is an implementation detail. A comment explaining why select-all is expected would help, since the primary assertion is that ArrowRight doesn't move focus.

Strengths

  • Correct and consistent fix across all 4 locations
  • Import cleanup done properly in ScrollArea files
  • 3 well-written regression tests with clear naming and consistent patterns
  • Tests verify user-visible behavior (focus stability, tooltip persistence, data-hovering), not internals
  • Proper async handling with flushMicrotasks()
  • The CompositeRoot test covers both focusin and keydown paths in one scenario

Recommended Action

  1. Add a regression test for the ScrollAreaScrollbar.tsx thumb click path
  2. Verify getTarget/nativeEvent aren't left as dead code in useHover.ts and useHoverReferenceInteraction.ts
  3. Consider the cosmetic suggestions for test clarity

Copy link
Copy Markdown
Contributor Author

@atomiks atomiks left a comment

Choose a reason for hiding this comment

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

Codex Review (GPT-5.4)

This is a bug-fix PR with secondary tests and react-ui changes. Reviewing the full branch against a freshly fetched master, I do not see any remaining branch-relevant issues: the final patch now makes the right distinction between React-synthetic target checks for hover logic and native composed-path target checks for true thumb-hit detection.

1. Bugs / Issues (None)

I did not find any concrete correctness, regression, or validation gaps that still need action before merge.

Root Cause & Patch Assessment

The final code path split looks correct now. ScrollAreaRoot, useHover, and useHoverReferenceInteraction all switch back to event.target specifically in React synthetic handlers where React’s retargeting is the semantic source of truth for “inside / active trigger” checks, while ScrollAreaScrollbar intentionally keeps a native target lookup for thumb-hit detection, which is the one place where the actual composed-path leaf matters more than the synthetic host target.

That same distinction is reflected in the tests now. The hover regressions cover the synthetic/native target mismatch directly, and the scrollbar regression covers the previously missing thumb-click path rather than only a happy-path hover case.

Test Coverage Assessment

I ran the targeted JSDOM suites for the touched areas:

  • pnpm test:jsdom ScrollAreaScrollbar --no-watch
  • pnpm test:jsdom useHover --no-watch
  • pnpm test:jsdom CompositeRoot --no-watch

Those checks line up well with the actual risk in this PR: hover-state retargeting, wrapper-trigger hover logic, scrollbar thumb-vs-track detection, and the shadow-hosted native-input behavior guarded by the CompositeRoot regression test.

Recommendation

Approve ✅

The bug-fix path now looks internally consistent, the earlier scrollbar test gap has been closed, and the final regression coverage is strong for the exact failure modes this PR is addressing.

@atomiks atomiks merged commit f06a277 into mui:master Apr 6, 2026
23 checks passed
@atomiks atomiks deleted the codex/scroll-area-hovering-target branch April 6, 2026 09:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: scroll area Changes related to the scroll area component. internal Behind-the-scenes enhancement. Formerly called “core”. type: bug It doesn't behave as expected. type: regression A bug, but worse, it used to behave as expected.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants