You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A Popover or Select that is open at mount restores focus to body instead of its trigger #10661
A Popover (in a DialogTrigger) or a Select that is open at mount (defaultOpen) restores focus to <body> when it closes, not to its trigger.
🤔 Expected Behavior?
Closing it returns focus to the trigger, as it does when the same popover was opened by pressing the trigger.
😯 Current Behavior
Load without focusing anything, press Escape, wait 600 ms. 5 of 5 runs each:
dialog open at mount (aria-expanded=true), Escape -> focus: BODY
select open at mount (aria-expanded=true), Escape -> focus: BODY
control, dialog opened by clicking the trigger, Escape -> focus: BUTTON#trigger
💁 Possible Solution
useRestoreFocus records the active element during render as the node to restore (react-aria/dist/private/focus/FocusScope.mjs:440-443). For a surface open at mount that is <body>, and the trigger is never considered. Falling back to the overlay's trigger when the recorded node is <body> would cover it.
Not the same as #10610 (a race between the restore frame and inert cleanup): nothing races here, and it happens on every run.
🔦 Context
Found while building a design system on React Aria Components. Observed in headless Chromium (Playwright 1.63, real key and mouse events) with react-aria-components 1.21.1 / react-aria 3.52.1 / react-stately 3.50.0 and no other code.
Reproduced this locally, as you mentioned it is because of useRestoreFocus. I think it would be reasonable to fall back to the overlay's trigger in that case, either via adding some logic to useRestoreFocus to find the focus scope's trigger if any, or expose a way for overlay components to pass such a fallback element down to FocusScope.
@LFDanLu I think searching for the trigger sounds reasonable, but have you guys talked about how to do that yet? Rob mentioned you don't want to introduce new props, which I can understand, but that opens up the problem of what to rely on for identity.
Edit: Nvm, there is a better way I think. Will close along with some other fixes for FocusScope 👍
Activity
LFDanLu commentedon Sep 30, 2026
Reproduced this locally, as you mentioned it is because of
useRestoreFocus. I think it would be reasonable to fall back to the overlay's trigger in that case, either via adding some logic touseRestoreFocusto find the focus scope's trigger if any, or expose a way for overlay components to pass such a fallback element down to FocusScope.nwidynski commentedon Oct 14, 2026
@LFDanLu I think searching for the trigger sounds reasonable, but have you guys talked about how to do that yet? Rob mentioned you don't want to introduce new props, which I can understand, but that opens up the problem of what to rely on for identity.
Edit: Nvm, there is a better way I think. Will close along with some other fixes for FocusScope 👍