Build a Debounced Autocomplete Search Bar
WaymoFrontend Engineer · OnsiteLast updated
This problem evaluates your ability to implement a robust, performant search component that handles asynchronous race conditions and user accessibility requirements.
Debounced Autocomplete Component
You are tasked with building an autocomplete search component. As a user types into an input field, the component should fetch suggestions from a remote API.
Requirements
- Debouncing: Ensure API requests are triggered only after the user has stopped typing for a specified delay (e.g., 300ms).
- Race Condition Handling: If a user types "ca", then "cat", and the "ca" request returns after the "cat" request, the UI must display only the results for "cat".
- Cancellation: If a new request is initiated, any pending or in-flight requests for previous, stale queries should be cancelled.
- Accessibility: The component must behave like a standard WAI-ARIA combobox, supporting keyboard navigation (Up/Down arrow keys) and Esc to close.
- Edge Cases: Handle rapid deletion (clearing the input), empty results, and network failures gracefully.
API Signature
Assume a mock function: fetchSuggestions(query: string, signal: AbortSignal): Promise.
Implementation
Provide a function or component structure that manages the state and effects. You may use React hooks or vanilla JavaScript with a class structure.
/**
* @param {HTMLInputElement} inputElement
* @param {HTMLElement} listContainer
* @param {Function} fetchSuggestions
*/
function setupAutocomplete(inputElement, listContainer, fetchSuggestions) {
// Implementation goes here
}
Example Flow
- User types 'A' -> debounce starts.
- User types 'B' -> first debounce timer cleared, new timer starts.
- Timer expires ->
fetchSuggestions('AB', signal)called. - User selects an item -> Input reflects selection, list closes.
Hints
Hint 1
Use a closure to hold the reference to the current AbortController so you can call .abort() on the previous request whenever a new one begins.
Hint 2
The 'input' event listener should trigger the debounced function, which subsequently manages the state update and API call logic.
Hint 3
Use 'aria-expanded', 'aria-controls', and 'role="listbox"' to ensure the component is accessible to screen readers.
Follow-up questions
- How would you implement local caching (memoization) to avoid redundant network requests for identical queries?
- How would you handle International Input Method Editors (IME), where multiple keystrokes compose a single character?
- How do you ensure the component behaves correctly if the user quickly focuses and blurs the input field?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.