Design a Reusable React Autocomplete Input: API, Portals, Debounce and Caching
Company: Airwallex
Role: Frontend Engineer
Category: System Design
Difficulty: medium
Interview Round: Technical Screen
Design an autocomplete search input for a web application: a text field that shows matching suggestions in a popup as the user types and lets the user pick one. Build it as a reusable React component. Assume the backend search API already exists.
The interviewer steered the discussion through the topics in the parts below: the backend API contract, the component architecture, throttling versus debouncing, local caching of results, and the component's public interface.
### Clarifying Questions
- What is being searched, and does each suggestion need rich rendering such as icons, secondary text or highlighted matches?
- Is selection single or multiple, and may the user submit free text that matches no suggestion?
- Roughly how many results can a query match, and how fast is the existing API?
- Will the component be used inside dialogs, scrolling panels or other popups?
- Which browsers and devices must be supported, and what accessibility standard applies?
### Part 1 — Backend API contract
The search API exists, but define the contract the component relies on: request parameters, response shape, pagination and the result limit.
```hint Pages that shift
Think about what happens to offset-based pages if the ranking changes between the first and the second request for the same query.
```
```hint Responses out of order
Responses for earlier keystrokes can arrive after later ones. Decide what the request or the response must carry so the client can tell which input a response belongs to.
```
#### What This Part Should Cover
- Request parameters and a minimal response shape
- The pagination model, and how the limit is chosen and capped
- Out-of-order responses, errors and rate limiting
### Part 2 — Component architecture
Break the component into an input, a label, a field wrapper, a popup, a portal and a portal manager. Explain each piece's responsibility, where the state lives, how the pieces communicate, and why the popup is rendered through a portal.
```hint Escaping the overflow
Picture the field inside a scrolling panel or a dialog that hides its overflow. Ask where the suggestion list must live in the DOM to be visible and on top.
```
```hint Popups inside popups
A dropdown can open inside a dialog that is itself a layer. Think about what has to coordinate stacking order, and which layer the Escape key should close.
```
#### What This Part Should Cover
- Responsibilities of each piece and where the state lives
- Portal rendering, positioning, and the portal manager's role in stacking and dismissal
- Keyboard navigation and screen-reader semantics for the combined input and list
### Part 3 — Throttling versus debouncing
Requests should not fire on every keystroke. Compare throttling and debouncing for this component, choose one, and explain how it fits with the rest of the request handling.
```hint Draw the timeline
Sketch a burst of fast keystrokes followed by a pause, and mark when requests fire under each technique.
```
#### What This Part Should Cover
- Definitions of both techniques and their request timelines
- Request volume versus how quickly results appear
- How the choice combines with request cancellation, a minimum query length and cache hits
### Part 4 — Local result caching
Cache results on the client. Compare three strategies: an LRU cache of recent queries, reusing the results of a cached query that is close to the current one by string distance, and showing popular results. When does each help, what can go wrong, and how would you combine them?
```hint One more character
When the user extends a query by one character, think about what a cached result for the shorter query can and cannot tell you.
```
```hint Close is not equal
Ask when results for a query that is merely similar to the current one would mislead the user.
```
#### What This Part Should Cover
- An LRU cache keyed by the normalized query: capacity, eviction and expiry
- Approximate reuse by prefix or string distance, and its limits
- Popular results for empty or short input and as a fallback, and how the three strategies combine
### Part 5 — React props and external interface
Define the component's props and external interface. Which components do you export to consuming teams, and which stay internal?
```hint What consumers will change
List what a consuming team will want to change (data source, item rendering, selection handling) and find the narrowest props that allow it.
```
```hint Exports are promises
Every exported component is an API you must keep stable. Decide which pieces consumers need to compose, and which would only let them break the component's invariants.
```
#### What This Part Should Cover
- Props: data source, controlled and uncontrolled state, callbacks and rendering customization
- Exported versus internal components and hooks
- Stability, accessible defaults and testability of the interface
### What a Strong Answer Covers
- A coherent flow from keystroke to rendered, selectable suggestions
- No stale or out-of-order results shown, under any network timing
- Accessibility built in: combobox semantics, keyboard support and focus handling
- Explicit trade-offs: request volume versus latency, cache freshness versus hit rate, flexibility versus API surface
- A small, stable public interface backed by internal components that can change freely
### Follow-up Questions
- How would you load more results as the user scrolls the suggestion list, and what happens if the query changes mid-scroll?
- How would you test the component, including debounce timing, out-of-order responses and accessibility?
- What changes if the page is rendered on the server?
- How should the popup behave on a phone, where the on-screen keyboard covers much of the screen?
Overview: Design a reusable autocomplete search input for a React application on top of an existing search API. The discussion covers the API contract with pagination and limits, the component and portal architecture, throttling versus debouncing, client-side result caching strategies, and the public props and exports.
Read the full Airwallex Frontend Engineer interview experience this question came from