components: Menu popover render + surface/motion split#77460
Conversation
Extract the @wordpress/components Menu changes from #76837: wrap menu content in MenuSurface, move variant styling and open animations to the inner surface so they are decoupled from the Ariakit Menu root (immediate close, no leave transition blocking scroll lock).
Use Ariakit Menu render to wrap merged props in MenuSurface inside MenuMotionRoot so open-only animations run on the outer shell. Merge trunk into PR branch.
Made-with: Cursor
Keep render + MenuMotionRoot/MenuSurface DOM; drop keyframe open-only CSS in favor of the same transition + data-enter / data-side rules as trunk, including exit transition. Made-with: Cursor
Made-with: Cursor
|
Size Change: +125 B (0%) Total Size: 7.75 MB 📦 View Changed
ℹ️ View Unchanged
|
|
Flaky tests detected in ce86bb5. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/24571891937
|
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Are you framing this as a temporary local patch for the upstream bug? The PR description is a bit contradictory on this point ("keeping the same motion behavior as I guess it's fine if it's meant as a quick temporary patch, But I also wonder if it's better to wait for the upstream fix or just prepare the new Base UI |
|
I'm suggesting this fix as the best compromise for the time being — the visual difference is limited, and the fix is real and needed in Dataviews if we want to start using the new If the issue is fixed upstream, we'll be able to remove the workaround. As we update to the |

Continues the same changes as #77450, with the head branch on
WordPress/gutenberginstead of a fork (GitHub does not support retargeting an existing PR from a fork to the upstream repo).See #76837 — extracted
@wordpress/componentsMenu work.Related context: mui/base-ui#4640 — describes a scroll-lock handoff bug when opening another modal overlay while an Ariakit
Menuis still closing; one mitigation is moving panel motion off the Ariakit root so scroll-lock cleanup is not delayed by leave transitions on that element.What?
Restructures
Menu.PopoverDOM: AriakitMenuuses arendercallback so merged props land on an innerMenuSurface, wrapped by an outerMenuMotionRoot. Panel motion stays transition-based liketrunk(slide + fade with enter and exit), driven bydata-enter/data-sideon the inner surface.Why?
Separates the Ariakit root (positioning, z-index, Windows High Contrast outline) from the visual panel (grid, chrome,
variant, overflow) while keeping the same motion behavior astrunk. The split also aligns with the kind of DOM layering discussed in mui/base-ui#4640 for healthier scroll-lock behavior across stacked overlays.Note
Close timing: with motion applied on
MenuMotionRoot(outside the AriakitMenuelement that coordinates scroll lock), Ariakit may not wait for the close CSS transition to finish before unmounting or running scroll-lock teardown. The exit animation can still play on the wrapper, but teardown timing may differ from a single-elementtrunkmenu—pay extra attention when opening another modal overlay while a menu is closing (see mui/base-ui#4640).How?
popover.tsx:renderreturns<MenuMotionRoot><MenuSurface { ...htmlProps } variant /></MenuMotionRoot>; popoverchildrenstill reach the surface through Ariakit’s merged props.styles.ts:Menu— thin shell styles only.MenuSurface— layout, elevation,overflow,variant.MenuMotionRoot—trunk-equivalent transition rules under@media not (prefers-reduced-motion), expressed with:has(> ${MenuSurface}[…])becausedata-*attributes live on the inner node.Implementation notes (optional)
:not(:has(> ${MenuSurface}[data-submenu])), matching trunk’s&:not([data-submenu])intent.DROPDOWN_MOTION_CSSfrom the shared dropdown motion tokens.Testing Instructions
npm run storybook:dev(or your usual Storybook workflow) with dependencies installed.Menustories under@wordpress/components.trunk.Testing Instructions for Keyboard
trunkexpectations.Screenshots or screencast
Note: animations in the screen recordings are purposefully slowed down for debugging reasons
Before: delayed scroll-unlock, visible exit animation
Kapture.2026-04-17.at.16.47.43.mp4
After: (no delayed scroll-unlock, no exit animation)
Kapture.2026-04-17.at.16.45.09.mp4
TODO / Follow-ups
Menuchanges, reconcile or supersede this PR as needed.Use of AI Tools
This PR description was updated with AI assistance (Cursor). Code should be reviewed on its own merits.