Machine coding
Build an Autocomplete Component
Difficulty: 🟡 Medium · Est. time:
45m· Tags:#input#async#a11y#debounce
Asked at: Google, Meta, Amazon, Airbnb · Related: System design: Autocomplete · debounce/throttle
1. The Question
Build a reusable autocomplete/typeahead input that fetches suggestions as the user types, is keyboard-accessible, and handles loading/error/empty states.
2. Requirements
Functional
Non-functional
3. Component API
type AutocompleteProps<T> = {
value: string;
onChange: (value: string) => void;
onSelect: (item: T) => void;
fetchSuggestions: (query: string, signal: AbortSignal) => Promise<T[]>;
getLabel: (item: T) => string;
debounceMs?: number; // default 250
minChars?: number; // default 1
};
4. Implementation Notes & Trade-offs
Debounce → a useDebouncedValue(value, 250) hook (or a debounced effect). Query only after the user pauses.
Race conditions → each fetch gets an AbortController; abort the previous one before firing a new one. Also guard by comparing the resolved query to the current input before setting state.
Highlighted index → track activeIndex; wire aria-activedescendant to the option id. Reset on new results. Scroll the active option into view.
Accessibility (combobox) → input has role="combobox", aria-expanded, aria-controls={listboxId}, aria-autocomplete="list". Listbox has role="listbox"; options role="option" with aria-selected. Announce result counts via aria-live="polite".
Match highlighting → split each label on the query and wrap matches in <mark> — never innerHTML (XSS).
Edge cases → empty input clears results; trailing whitespace; rapid backspace (cache hits); no-results message; error retry; click-outside via a pointerdown listener; don't lose focus on option click (use onMouseDown preventDefault).
Cleanup → abort in-flight requests and clear timers on unmount.
5. What Interviewers Probe
- Debounce vs throttle here?
- How do you kill stale responses? (AbortController + query guard)
- Full keyboard model + focus handling.
- ARIA combobox correctness.
- Why not
dangerouslySetInnerHTMLfor highlighting? - How do you make it reusable (headless vs styled)?
6. Curated Resources
- ARIA APG: combobox ⭐ — the exact a11y contract
- MDN: AbortController
- System-design version — the scaled discussion
- GreatFrontEnd: Autocomplete