Skip to content

[popups] Fix positioning and viewport edge cases#4925

Merged
atomiks merged 2 commits into
mui:masterfrom
atomiks:codex/popups-positioning-viewport-fixes
May 27, 2026
Merged

[popups] Fix positioning and viewport edge cases#4925
atomiks merged 2 commits into
mui:masterfrom
atomiks:codex/popups-positioning-viewport-fixes

Conversation

@atomiks

@atomiks atomiks commented May 27, 2026

Copy link
Copy Markdown
Contributor

Updates shared popup behavior so keep-mounted/custom-anchor positioning, preventUnmountOnClose reopen cycles, and viewport API docs are handled consistently across popup components.

Changes

  • Observes the actual positioning reference for keep-mounted popups so custom anchors trigger updates.
  • Clears preventUnmountOnClose when popups reopen, including controlled external reopens.
  • Shares active-trigger open-state updates across popup stores and menu root.
  • Prevents disabled hover popover triggers from opening.
  • Exports consistent viewport props/state types and regenerates popup viewport API docs.

@atomiks atomiks added component: menu Changes related to the menu component. docs Improvements or additions to the documentation. type: bug It doesn't behave as expected. component: tooltip Changes related to the tooltip component. component: dialog Changes related to the dialog component. component: popover Changes related to the popover component. component: preview card Changes related to the preview card component. labels May 27, 2026
@pkg-pr-new

pkg-pr-new Bot commented May 27, 2026

Copy link
Copy Markdown

commit: f9acaa4

@code-infra-dashboard

code-infra-dashboard Bot commented May 27, 2026

Copy link
Copy Markdown

Bundle size

Bundle Parsed size Gzip size
@base-ui/react ▼-12B(0.00%) 🔺+7B(0.00%)

Details of bundle changes

Performance

Total duration: 1,115.40 ms -106.36 ms(-8.7%) | Renders: 50 (+0) | Paint: 1,705.55 ms -153.17 ms(-8.2%)

Test Duration Renders
Scroll Area mount (300 instances) 66.00 ms ▼-28.80 ms(-30.4%) 3 (+0)
Menu open (500 items) 70.95 ms ▼-19.23 ms(-21.3%) 12 (+0)
Popover mount (300 instances) 62.88 ms ▼-16.04 ms(-20.3%) 1 (+0)

9 tests within noise — details


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

@atomiks
atomiks marked this pull request as ready for review May 27, 2026 11:40

@flaviendelangle flaviendelangle left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

PR #4925 Review — [popups] Fix positioning and viewport edge cases

Scope: 22 files, +276/−91. Three behavioral fixes (custom-anchor tracking, preventUnmountOnClose reset-on-reopen, disabled-hover) + a viewport type/namespace refactor + a docs/JSDoc correction. Reviewed by four specialized agents (code, tests, comments, types); their key claims were independently re-verified (typescript, docs:api, eslint, prettier, and regression runs that revert each fix).

Critical Issues (0)

None. All three fixes were empirically confirmed to fail on master and pass on the branch — they are genuine regression guards, not tautological.

Important Issues (1)

1. Menu's reset-on-reopen behavior is untested — MenuRoot.tsx:314
This PR replaced Menu's hand-written active-trigger block with the shared setPopupOpenState, which newly resets preventUnmountingOnClose = false on open. Menu fully supports preventUnmountOnClose (MenuRoot.tsx:248-250), making it the highest-regression-risk component — it's the only one whose call site is bespoke rather than a uniform store method (Dialog/Tooltip/PreviewCard all call setPopupOpenState identically inside their store classes). The only existing Menu test (MenuRoot.test.tsx:1562) covers the actionsRef.unmount() path, not reopen-then-normal-close.
Recommend adding a Menu analog of PopoverRoot.test.tsx:644: open → close once with a gated preventUnmountOnClose() (menu stays mounted) → reopen via trigger → normal-close → assert queryByRole('menu') is null.

Suggestions (3, all optional)

  1. PreviewCardViewport namespace orderPreviewCardViewport.tsx:85-88 re-exports State before Props; the other three viewports use Props then State. Cosmetic (alias semantics are order-independent) but it propagates into the generated preview-card/types.md ordering. One-line tidy for intra-PR symmetry.
  2. Direct coverage for Dialog/Tooltip/PreviewCard reset-on-reopen — currently rely on Popover as a proxy. Defensible since they share the store-level call site; a single mirrored test would close the loop cheaply.
  3. Undocumented "why" — the functional core of the bug fix (popupStoreUtils.ts:124-126 and the open ? false : … sync at :270) has no comment. A one-liner like "Opening clears any pending prevent-unmount request from a previous close cycle" would help future maintainers.

⚠️ One agent finding to disregard

The type-design agent suggested collapsing the multi-line extends BaseUIComponentProps<…> in PreviewCardViewportProps onto one line. I ran pnpm prettier --check — it passes as-is; the wrap is forced by line length (PreviewCard's identifiers are longer than the siblings'). Collapsing it would fail formatting. Leave it.

Strengths

  • Docs fix corrects a real, pre-existing error. data-activation-direction was documented as top/bottom, but the producer (usePopupViewport.tsx:285) emits right/left + down/up with an '' fallback. The PR fixes the tokens, fixes a missing-$ typo in the popover variant, adds the '' option, and unifies all four files with the already-correct Menu definition.
  • domReferencereference (useAnchorPositioning.ts:507) correctly tracks custom anchors for keepMounted popups (a custom anchor sets elements.reference via setPositionReference while domReference stays the trigger), and aligns the keepMounted path with the non-keepMounted whileElementsMounted path. Safe for virtual elements.
  • !disabled hover guard (PopoverTrigger.tsx:83) brings Popover in line with Tooltip/Menu/SubmenuTrigger, which already guard this way; PreviewCard's <a> trigger has no disabled concept. No shared abstraction warranted for a one-token guard.
  • Type refactor finishes a partial migration to the codebase's dominant convention (~180 components use top-level interface + namespace alias); instant unions are correctly differentiated per component (verified against each store), and the string widening for activationDirection matches its runtime provider.
  • Verification clean: pnpm typescript, pnpm docs:api ("No files needed updating"), pnpm eslint, pnpm prettier, plus PopoverRoot/PopoverTrigger/PopoverPositioner/Menu/Tooltip/PreviewCard test suites all pass.

Recommended Action

  1. Add the Menu reset-on-reopen test (the one Important item).
  2. Optionally apply suggestions 1–3.
  3. Everything else is merge-ready.

@atomiks
atomiks force-pushed the codex/popups-positioning-viewport-fixes branch from acd92a9 to 11a1b53 Compare May 27, 2026 13:44
@netlify

netlify Bot commented May 27, 2026

Copy link
Copy Markdown

Deploy Preview for base-ui ready!

Name Link
🔨 Latest commit 11a1b53
🔍 Latest deploy log https://app.netlify.com/projects/base-ui/deploys/6a16f532cdda270008911581
😎 Deploy Preview https://deploy-preview-4925--base-ui.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.

@netlify

netlify Bot commented May 27, 2026

Copy link
Copy Markdown

Deploy Preview for base-ui ready!

Name Link
🔨 Latest commit f9acaa4
🔍 Latest deploy log https://app.netlify.com/projects/base-ui/deploys/6a16f5f412143e00083e8f40
😎 Deploy Preview https://deploy-preview-4925--base-ui.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.

@atomiks
atomiks merged commit 0ce0930 into mui:master May 27, 2026
23 checks passed
@atomiks
atomiks deleted the codex/popups-positioning-viewport-fixes branch May 27, 2026 14:35
@michaldudak michaldudak mentioned this pull request Jun 17, 2026
@michaldudak michaldudak removed the docs Improvements or additions to the documentation. label Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: dialog Changes related to the dialog component. component: menu Changes related to the menu component. component: popover Changes related to the popover component. component: preview card Changes related to the preview card component. component: tooltip Changes related to the tooltip component. type: bug It doesn't behave as expected.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants