CodePark/ questions / Classic designs
START PRACTICINGPRACTICE
Frontend question · Frontend system design › Classic designs

Design an autocomplete / typeahead search component, such as the search box on a large e-commerce site.

Build a reusable Autocomplete component that debounces input, caches results, cancels stale requests and follows the ARIA combobox pattern.

Requirements:

  • Suggestions appear as the user types.
  • Keyboard navigation works.
  • Matching text is highlighted.
  • Recent searches show when the input is empty.
  • It works on mobile and is accessible.

Non-functional requirements:

  • Suggestions appear in about 100 to 200 ms.
  • Server load stays low.
  • It is reusable across products.

Architecture: an Autocomplete component with an input, a listbox popup and option renderers. A hook manages the query, the results, the active index and the open state. A data source function is injected (passed in), so the same component works for users, products or places.

API: GET /suggest?q=lap&limit=8. It returns items with an id, label, type and highlight ranges.

Optimisations:

  • Debounce the input, about 150 to 300 ms. Debounce means wait until the user stops typing for that long before sending.
  • Set a minimum query length.
  • Cancel stale requests with AbortController, or ignore responses that arrive out of order.
  • Keep an in-memory LRU cache keyed by query, so backspacing is instant. LRU (least recently used) means the entries unused for longest are dropped first.
  • Filter prefix results locally from an earlier, broader query. For example, results for "lapt" can be filtered from the results for "lap".

Accessibility: use the combobox pattern with role="combobox", aria-expanded, aria-controls and aria-activedescendant. Add a live region that announces the number of results. A live region is an area that screen readers read aloud when it changes.

Trade-offs: a longer debounce means fewer requests, but the box feels slower.

  • Debounce input, set a minimum length, and cancel or ignore stale responses.
  • Cache results on the client per query.
  • Use the ARIA combobox pattern with aria-activedescendant.
  • Inject the data source so the component can be reused.
  • Handle loading, empty and error states.