diff --git a/packages/client/ui-settings-general/src/client/SettingsRoot.tsx b/packages/client/ui-settings-general/src/client/SettingsRoot.tsx index 762747500d..5c5498738e 100644 --- a/packages/client/ui-settings-general/src/client/SettingsRoot.tsx +++ b/packages/client/ui-settings-general/src/client/SettingsRoot.tsx @@ -54,7 +54,7 @@ function SettingsPanel({ rows, renderSlot, activeId, onSelect, onClose }: PanelP return () => { document.removeEventListener('keydown', onKeyDown) } }, [onClose]) - // Baseline focus management: entering the dialog lands on the close button. + // Entering the dialog focuses the close button; the root restores its trigger on close. const closeButton = useRef(null) useEffect(() => { closeButton.current?.focus() }, []) @@ -106,10 +106,17 @@ export function SettingsRoot(props: SettingsRootComponentProps) { const [open, setOpen] = useState(false) const [activeId, setActiveId] = useState(undefined) const [completedOnboarding, setCompletedOnboarding] = useState>(() => new Set()) + const triggerButton = useRef(null) + const wasOpen = useRef(open) const close = useCallback(() => { setOpen(false) setActiveId(undefined) }, []) + // Restore after the close commit, when the dialog can no longer own focus. + useEffect(() => { + if (wasOpen.current && !open) triggerButton.current?.focus() + wasOpen.current = open + }, [open]) const openSection = useCallback((id: string) => { setActiveId(id) setOpen(true) @@ -142,6 +149,7 @@ export function SettingsRoot(props: SettingsRootComponentProps) { return ( <>