Debounced Search / Autocomplete

Objective

Implement a responsive, accessible search box that fetches results from a remote API. You’ll start with the basics (functionality) and progressively build toward production-grade quality (correctness, UX, accessibility, and architecture).

Context

This exercise reflects one of the most common frontend interview patterns: building a small but realistic component that tests core fundamentals — async control, React state management, and attention to detail.

Stage 1 — Core Functionality

Goal

Build a search input that queries a mock API with a debounce and basic UI states.

What to Implement

  • A text input that updates a search query
  • Debounce API requests (~300ms)
  • Show loading, empty, and error states
  • Render results when available
  • Clear results when input is cleared

What You’re Practicing

  • React state modeling (query, results, status, error)
  • Effect cleanup and dependency management
  • Basic async workflows and UI state transitions

How Interviewers Evaluate

CategoryWhat They’re Watching For
Technical correctnessDebounce works, fetch occurs once per user intent
Code organizationClean hooks/effects, minimal duplication
Error handlingGraceful recovery from failed requests
CommunicationClear reasoning behind debounce placement and timings

Self-check

  • Does typing “ab” quickly result in one API call for “ab”?
  • Does the UI avoid flickering between states?
  • Can you explain your state structure clearly?

Stage 2 — Concurrency & Race Safety

Goal

Prevent outdated responses from overwriting newer ones when multiple requests overlap.

What to Implement

  • Cancel in-flight requests using AbortController, or track request IDs
  • Only apply the latest response to state
  • Ensure cleanup happens on query change or unmount

What You’re Practicing

  • Safe concurrent async handling
  • Reasoning about race conditions in React effects
  • Coordinating cleanup logic

How Interviewers Evaluate

CategoryWhat to Look For
Async understandingCorrect use of cancellation or token tracking
Edge-case handlingNo flicker or stale data
Problem-solvingAwareness of real-world network conditions
Depth of reasoningCan articulate why the bug occurs, not just fix it

Self-check

  • Type “react” then delete to “re” — does “react” data ever reappear later?
  • Can you explain the lifecycle of an aborted request in your code?

Stage 3 — Interaction & Accessibility

Goal

Support full keyboard and screen-reader interaction for the autocomplete experience.

What to Implement

  • Keyboard navigation (Up/Down arrows, Enter, Escape)
  • Mouse click selection
  • Proper ARIA roles and attributes (combobox, listbox, option, etc.)
  • Focus management: input regains focus after selection

What You’re Practicing

  • Accessible component design
  • Managing keyboard state (activeIndex, isOpen)
  • Building inclusive interactions

How Interviewers Evaluate

CategoryWhat to Look For
AccessibilityImplements correct ARIA patterns
UX polishPredictable focus behavior, smooth transitions
Structural thinkingClear separation of input vs popup logic
InitiativeBrings up a11y without being prompted

Self-check

  • Can you use the component entirely with a keyboard?
  • Does it meet the minimal WAI-ARIA combobox pattern?
  • Does the focus behave predictably when selecting an item?

Stage 4 — Architecture & Performance

Goal

Show that your implementation scales, both technically and organizationally.

What to Implement

  • Extract logic into a reusable useAutocomplete hook or headless component
  • Add lightweight caching for repeated queries
  • Use React.memo or stable callbacks to prevent re-renders
  • Optionally prefetch results on focus

What You’re Practicing

  • Abstraction design
  • Reusability and API design for other teams
  • Performance awareness in real applications

How Interviewers Evaluate

CategoryWhat to Look For
ArchitectureHeadless hook, clean interface
PerformanceEfficient re-renders and memoization
ReusabilityFlexible, documented API surface
CommunicationExplains trade-offs (e.g., caching vs freshness)

Self-check

  • Can you describe how your useAutocomplete hook could be tested independently?
  • How would you expose this as a reusable component within a design system?
  • Does typing feel instantaneous under heavy load?

Stage 5 — Reflection & Testing Strategy

Goal

Demonstrate the ability to self-critique and reason about trade-offs.

Reflection prompts

  • What are the main failure cases in your current design?
  • How would you test your debounce logic with fake timers?
  • What integration tests would ensure correct behavior across states?
  • What would you prioritize next if you had more time (e.g., SSR, analytics, cache persistence)?

How Interviewers Evaluate

CategoryWhat to Look For
Self-awarenessIdentifies trade-offs and limitations
Testing mindsetThinks in terms of verification and confidence
CommunicationReflects clearly on decisions made under pressure
DepthProposes meaningful extensions, not arbitrary polish

Self-check

Write a short “postmortem”:

  • What went well technically?
  • What you’d refactor?
  • What production hardening steps you’d take (metrics, retries, a11y audit)?

Rubric

StageFocusEvaluation EmphasisBar for Senior
1Debounce & UI statesBasic correctness, clarityFlawless base behavior
2Async safetyRace handling, stabilityNo stale data, clean effects
3Accessibility & UXKeyboard + ARIAOperable and inclusive
4ArchitectureReusable, performant codeScalable design
5ReflectionTesting and reasoningClear ownership mindset

Senior-level performance means:

  • You finish Stage 2 quickly and solidly
  • You voluntarily introduce Stage 3–4 improvements
  • You can justify trade-offs out loud
  • You think like an owner — not just a coder