Autocomplete looks like a solved problem until you watch the network tab: a request per keystroke, and — the classic — results for "vel" arriving after results for "velocity" and overwriting them. The user typed more, the UI showed less. That's not a style bug; it's a race condition shipping to production on most search boxes.
Velocity X's search-input-suggestions handles the three failure modes in one file: request spam, out-of-order responses, and the keyboard model.
The Money Pattern
Debounce controls when you fetch; AbortController guarantees stale responses can never land:
useEffect(() => {
if (query.length < 2) { setResults([]); return; }
const ctrl = new AbortController();
const t = setTimeout(async () => {
try {
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`,
{ signal: ctrl.signal });
setResults(await res.json());
} catch (e) {
if (e.name !== 'AbortError') setResults([]);
}
}, 150);
return () => { clearTimeout(t); ctrl.abort(); };
}, [query]);
The cleanup function is the whole fix: every new keystroke cancels both the pending timer and any in-flight request. Out-of-order results become impossible — not unlikely, impossible — because a superseded request is dead before its response arrives. No sequence counters, no "latest query" refs.
The Catch
The dropdown is where accessibility goes to die. The pattern has a name — combobox — and a contract: role="combobox" with aria-expanded on the input, role="listbox" on the list, arrow keys moving an aria-activedescendant highlight while focus stays in the input so typing never stops working. Moving real focus into the list is the most common way to break it.
And 150ms is a starting point, not a law: local/in-memory search wants no debounce at all, a rate-limited API wants 300ms. Debounce is a cost dial, so measure the API you're actually calling.
The Verdict
Autocomplete is a cancellation problem wearing a UI. Debounce the timer, abort the fetch, keep focus in the input — three decisions, all in the cleanup function. The finished combobox lives in Velocity X's Forms category, with standard-searchable-select-menu next door when the job is picking from a known list instead of searching an index.









