From 9ae4b5415535865c041f5059a73b1a2e62bff8b8 Mon Sep 17 00:00:00 2001 From: Colin Dawson Date: Mon, 16 Feb 2026 16:17:48 +0000 Subject: [PATCH] Fixed the keyboard stealing issue --- src/components/common/SelectableList.tsx | 34 ++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/components/common/SelectableList.tsx b/src/components/common/SelectableList.tsx index 0ae0fdb..43e5969 100644 --- a/src/components/common/SelectableList.tsx +++ b/src/components/common/SelectableList.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useRef } from "react"; +import React, { useCallback, useEffect, useRef } from "react"; export interface SelectableListProps { items: T[]; @@ -12,10 +12,17 @@ export const SelectableList = ( ): JSX.Element => { const { items, selectedValue, renderLabel, onSelect } = props; + // Track focus state of the list itself const listRef = useRef(null); + const isFocusedRef = useRef(false); + + // One ref per item so we can focus + scroll it + const itemRefs = useRef<(HTMLLIElement | null)[]>([]); const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { + // Ignore keyboard input unless the list itself is focused + if (!isFocusedRef.current) return; if (!items.length) return; const currentIndex = selectedValue ? items.indexOf(selectedValue) : -1; @@ -37,11 +44,28 @@ export const SelectableList = ( [items, selectedValue, onSelect], ); + // Only focus the selected item if the list itself already has focus + useEffect(() => { + if (!isFocusedRef.current) return; // Do NOT steal focus + if (!selectedValue) return; + + const index = items.indexOf(selectedValue); + if (index < 0) return; + + const el = itemRefs.current[index]; + if (el) { + el.focus({ preventScroll: false }); + el.scrollIntoView({ block: "nearest" }); + } + }, [items, selectedValue]); + return (
    (isFocusedRef.current = true)} + onBlur={() => (isFocusedRef.current = false)} onKeyDown={handleKeyDown} > {items.map((item, index) => { @@ -49,7 +73,13 @@ export const SelectableList = ( const className = isSelected ? "selected" : ""; return ( -
  • onSelect(item)} className={className}> +
  • (itemRefs.current[index] = el)} + tabIndex={isSelected ? 0 : -1} + onClick={() => onSelect(item)} + className={className} + > {renderLabel(item)}
  • );