Skip to content

Stack dialogs and their overlays above whatever else is open - #251

Merged
einari merged 2 commits into
mainfrom
fix/dialog-stacking-zindex
Sep 7, 2026
Merged

Stack dialogs and their overlays above whatever else is open#251
einari merged 2 commits into
mainfrom
fix/dialog-stacking-zindex

Conversation

@einari

@einari einari commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Fixed

  • A second dialog opened while the first is still visible now stacks above it, instead of colliding on the same static z-index and relying on incidental DOM paint order.
  • A dropdown, date picker, or tooltip opened inside a dialog now stacks above whichever dialog tier it is actually nested in - including a dialog that was itself opened while another dialog was still open, which the single static overlay token never accounted for.

Context

Components 3 kept overlay panels above their dialog with useOverlayZIndex, a raise-only floor over PrimeReact's own ZIndexUtils registry (#123, PR #117, 2.6.2). Components 4 moved Dialog/Dropdown/DatePicker off PrimeReact onto React Aria, and useOverlayZIndex was removed as redundant along with everything else PrimeReact-specific - but nothing replaced the registry it depended on. A single dialog was never affected (there was only ever one static tier to stack above), which is why this went unnoticed: it only shows up with two dialogs open at once, or an overlay opened from the second one.

Adds a small open-dialog registry (Source/Dialogs/dialogStack.ts) that assigns each currently visible dialog a strictly increasing tier regardless of where in the tree it was opened from, and a DialogStackContext dialogs provide their resolved z-index through so nested overlay-producing components can stack relative to their actual dialog tier instead of a single static token. Internal wiring only - no public API change, so this ships as a patch.

Dialog, Dropdown, DatePicker, and Tooltip each used a single static
z-index token, so a second dialog opened while the first is still
visible collided on the exact same value - which one painted on top
was incidental DOM order, not a deliberate stacking rule. A dropdown
or date-picker opened inside that second dialog had the same problem
one level down: it stacked above its own dialog's static tier, but
not above a dialog elevated beyond that tier.

This is the gap left behind when Components 4 moved Dialog/Dropdown/
DatePicker off PrimeReact and onto React Aria: PrimeReact's own
ZIndexUtils registry used to assign each newly opened overlay a
strictly higher value, and the old useOverlayZIndex hook only ever
backstopped that registry with a floor - it relied on PrimeReact
doing the real work, so nothing replaced it when PrimeReact did.

Add a small open-dialog registry (openDialogTier/closeDialogTier)
that assigns each currently visible dialog a strictly increasing
tier regardless of where in the tree it was opened from, and a
DialogStackContext dialogs provide their resolved z-index through so
Dropdown/DatePicker/Tooltip can stack their own popovers relative to
whichever dialog tier they are actually nested in, rather than a
single static overlay token that only ever accounted for one.

A single, non-nested dialog is unaffected - it still resolves to the
same 1100/1200 values the static tokens produced before.
@einari einari added the patch label Sep 7, 2026
Common (Tooltip, DatePicker) importing from Dialogs crossed a hard
module-graph boundary the package's own CI enforces: a slot family's
private internals stay private to that family, and only the neutral
renderer/ layer is meant to be shared across families - exactly what
RendererContext.tsx already is for unstable_useOverlayEnvironment,
which every one of these four implementations already imports from
there. dialogStack.ts and DialogStackContext.ts have no dependency
beyond React, so they belong there for the same reason.
@einari
einari merged commit 7d32c9c into main Sep 7, 2026
41 checks passed
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