diff --git a/src/components/SearchModal.tsx b/src/components/SearchModal.tsx index 2e6f47a43..df234a45e 100644 --- a/src/components/SearchModal.tsx +++ b/src/components/SearchModal.tsx @@ -65,19 +65,21 @@ function CommandSearchInput({ isFullHeight: boolean onToggleFullHeight: () => void }) { - const { closeSearch } = useSearchContext() + const { isOpen, closeSearch } = useSearchContext() const { refine } = useSearchBox() const { searchQuery, setSearchQuery } = useSearchFilters() const hasQuery = searchQuery.trim().length > 0 const inputRef = React.useRef(null) React.useEffect(() => { + if (!isOpen) return + const frame = requestAnimationFrame(() => { inputRef.current?.focus({ preventScroll: true }) }) return () => cancelAnimationFrame(frame) - }, []) + }, [isOpen]) const clearSearch = React.useCallback(() => { setSearchQuery('') @@ -295,7 +297,7 @@ const searchModalTransitionMs = 140 export function SearchModal() { const { isOpen, closeSearch } = useSearchContext() - const contentRef = React.useRef(null) + const returnFocusRef = React.useRef(null) const bodyPointerEventsRef = React.useRef('') const [shouldRenderSearch, setShouldRenderSearch] = React.useState(isOpen) const [isFullHeight, setIsFullHeight] = React.useState(() => { @@ -327,20 +329,6 @@ export function SearchModal() { return () => window.clearTimeout(timeout) }, [isOpen]) - React.useEffect(() => { - if (!isOpen) { - return - } - - const frame = requestAnimationFrame(() => { - contentRef.current - ?.querySelector('input[type="search"]') - ?.focus({ preventScroll: true }) - }) - - return () => cancelAnimationFrame(frame) - }, [isOpen]) - React.useEffect(() => { if (typeof document === 'undefined') { return @@ -398,11 +386,27 @@ export function SearchModal() { /> { + // The input owns focus; the dialog has no Radix Trigger to restore. + returnFocusRef.current = + document.activeElement instanceof HTMLElement + ? document.activeElement + : null + event.preventDefault() + }} + onCloseAutoFocus={(event) => { + event.preventDefault() + if ( + document.activeElement === document.body && + returnFocusRef.current?.isConnected + ) { + returnFocusRef.current.focus({ preventScroll: true }) + } + }} onInteractOutside={(event) => { if (isSearchModalPortalTarget(event.target)) { event.preventDefault()