Skip to content

fix: close Popover when focus escapes outside while trapFocus is enabled#35995

Draft
petdud wants to merge 1 commit intomicrosoft:masterfrom
petdud:fix/popover-close-on-focus-escape
Draft

fix: close Popover when focus escapes outside while trapFocus is enabled#35995
petdud wants to merge 1 commit intomicrosoft:masterfrom
petdud:fix/popover-close-on-focus-escape

Conversation

@petdud
Copy link
Copy Markdown
Contributor

@petdud petdud commented Apr 16, 2026

Previous Behavior

When a Popover has trapFocus enabled and focus escapes outside (e.g. via browser address bar Cmd+L, dev tools, OS-level focus changes, or a keyboard shortcut that programmatically moves focus), the popover remains open in a broken "zombie" state.

This is especially problematic for popovers with interactive content like search inputs — once focus escapes, Tabster's focus trap fights the user: clicking back into the page outside the popover causes Tabster to redirect focus within ~100ms, making it impossible to type or interact. The popover is visually present but functionally dead, and the user has no recovery path other than pressing Escape (if they know about it).

New Behavior

When legacy trapFocus is enabled and focus moves outside both the popover content and trigger, the popover automatically closes via a document-level focusin listener. This fires before Tabster can redirect focus back, so the popover dismisses cleanly instead of entering the broken state.

  • Only active for legacy trap focus (trapFocus: true without inertTrapFocus) — inertTrapFocus allows spec-compliant focus escape to browser toolbar
  • Uses elementContains (virtual-parent-aware) so portaled content (nested menus, dropdowns, dialogs) opened from inside the popover is correctly treated as "inside"
  • Guards against race conditions during initial open (skips when contentRef is not yet mounted)
  • Added native FocusEvent to OpenPopoverEvents union type
  • No new props needed

Related Issue(s)

@petdud petdud force-pushed the fix/popover-close-on-focus-escape branch from 2aea379 to 9ad4d97 Compare April 16, 2026 13:02
@petdud petdud force-pushed the fix/popover-close-on-focus-escape branch from 9ad4d97 to 20020e9 Compare April 16, 2026 13:31
@@ -0,0 +1,7 @@
{
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Avatar Converged 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Avatar Converged.badgeMask.normal.chromium.png 5 Changed
vr-tests-react-components/Charts-DonutChart 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Charts-DonutChart.Dynamic - Dark Mode.default.chromium.png 7530 Changed
vr-tests-react-components/Charts-DonutChart.Dynamic.default.chromium.png 5581 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default.submenus open.chromium.png 413 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default - RTL.submenus open.chromium.png 404 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 731 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 731 Changed
vr-tests-react-components/ProgressBar converged 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - Dark Mode.default.chromium.png 98 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness.default.chromium.png 145 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - High Contrast.default.chromium.png 191 Changed
vr-tests-react-components/TagPicker 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled - High Contrast.chromium.png 1319 Changed
vr-tests-react-components/TagPicker.disabled - Dark Mode.disabled input hover.chromium.png 658 Changed
vr-tests-react-components/TagPicker.disabled.disabled input hover.chromium.png 677 Changed

There were 3 duplicate changes discarded. Check the build logs for more information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant