fix(portal): keep nested floating layers above inline containers - #219
Merged
Merged
Conversation
Modal, Slideover, Drawer and Popover rendered with portal={false} hid
every floating layer opened inside them (Select, DatePicker,
DropdownMenu, Tooltip, a nested Modal, ...) whenever an ancestor set a
z-index above 50. The layers were portalled to <body> at z-50 while the
inline panel belonged to the higher stacking context.
While such a container is open, nested layers now mount into a host
placed right before its panel, in the same stacking context and one
level above it. The host is removed once the panel has unmounted, so the
closed DOM is unchanged, and portalled containers are not affected.
Closes #217
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Modal,Slideover,DrawerandPopoverrendered withportal={false}hid every floating layer opened inside them whenever an ancestor set az-indexabove 50. ASelectinside aSlideoverbody opened, but its list stayed invisible behind the panel.The nested layers were portalled to the end of
<body>withz-50, while the inline panel belonged to the ancestor's higher stacking context, so the whole panel painted above them. TheScrollAreain the body was not involved: the list isposition: fixedand is not clipped byoverflow: hidden.Closes #217
Type of change
Changes
PortalScope(not exported). While active, it renders an empty host element withfixed top-0 left-0 z-51and points every nested portal without an explicit target at that host.Modal,Slideover,Drawer,Popover: withportal={false}, the content is wrapped inPortalScope. The host sits right before the panel (before the overlay for a scrollableModal), in the same stacking context and one level above it.space-y/divide-ymargins and borders to the trigger and the panel.portalare unchanged: no host is rendered and nested layers still portal to<body>.z-indexabove the panel (and above the overlay of a scrollableModal), host removed after closing. The placement,z-indexand removal tests fail ondev; the no-host tests pass on both and guard against the host leaking into closed or portalled containers.CHANGELOG.mdentry under[Unreleased].Checklist
Closes #…)pnpm checkpasses (0 errors, 0 warnings)pnpm lintpassespnpm testpassesCHANGELOG.mdunder[Unreleased]*.types.ts, Material 3 design tokens)Screenshots / notes
Verified in Chromium against
dev, with the container insiderelative z-[60]:Select,SelectMenu,DatePicker,DateRangePicker,DropdownMenu,Popover,Tooltip,ContextMenu, a nestedModalandLightboxare fully visible inside all four containers and a scrollableModal(fully or partly hidden ondev).ScrollArea, the drawer body or the page scrolls.dev. Layout of the parent (space-y,divide-y,flex gap, first/middle/last position) is identical when closed and open.Selectboth open on first render (host is present in the SSR HTML, no hydration warnings), and aPopoverwithportal={false}nested in aSlideoverwithportal={false}.Known limits:
z-indexis raised above 51 throughui.contentstill hides nested layers, as before.:nth-childselectors in its parent count one extra element.Out of scope:
Tour,NavigationMenuandToastercan show the same symptom through their ownz-index, but are left unchanged.