Skip to content

[Bug]: Dialog - stale aria-hidden breaks focus trap when closing stacked non-nested dialogs #35985

@mohkshu

Description

@mohkshu

Component

Dialog

Package version

9.73.7

React version

18

Environment

System:
    OS: Windows 11 10.0.26100
    CPU: (20) x64 12th Gen Intel(R) Core(TM) i9-12900H
    Memory: 16.53 GB / 31.69 GB
  Browsers:
    Chrome: 146.0.7680.178
    Edge: Chromium (142.0.3595.53)
    Firefox: 149.0.2 - C:\Program Files\Mozilla Firefox\firefox.exe
    Internet Explorer: 11.0.26100.7309
  npmPackages:
    @fluentui/react-components: ^9.0.0 => 9.72.9 
    @fluentui/react-icons: ^2.0.312 => 2.0.316 
    @types/react: ^17 => 17.0.90 
    @types/react-dom: ^17.0.26 => 17.0.26 
    react: ^18 => 18.3.1 
    react-dom: ^18 => 18.3.1

Current Behavior

When two or more independent (non-nested) Dialog components are stacked, closing the top dialog leaves the underlying dialog with a stale aria-hidden="true" on its portal node. This breaks the focus trap — focus jumps back to the original page trigger instead of returning to the underlying dialog.

Root cause (investigation)

Tabster's modalizer sets aria-hidden="true" on everything outside the active dialog. When the top dialog unmounts, the modalizer doesn't clean up the stale attribute on the underlying dialog's portal. The browser then blocks focus restoration into the aria-hidden subtree.

Workaround

We're using a useLayoutEffect hook that runs synchronously after the top dialog unmounts to:

Find the topmost remaining dialog by z-index
Remove aria-hidden from its portal container
Focus the first real focusable element (excluding [data-tabster-dummy])
This works but relies on internal DOM structure and is fragile against future changes.

Expected Behavior

Closing the top dialog should restore focus to the underlying dialog and its focus trap should re-engage.

Reproduction

https://stackblitz.com/edit/pxkb6cxd?file=src%2FApp.tsx

Steps to reproduce

  1. Render two independent Dialog components (not nested — siblings at the root level)
  2. Open Dialog 1
  3. From inside Dialog 1, programmatically open Dialog 2 (modalType="alert")
  4. Close Dialog 2
  5. Focus should return to Dialog 1, but instead it jumps to the page-level trigger button

Are you reporting an Accessibility issue?

None

Suggested severity

Medium - Has workaround

Products/sites affected

No response

Are you willing to submit a PR to fix?

no

Validations

  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
  • The provided reproduction is a minimal reproducible example of the bug.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions