Back to path
SmallWeekend build ~6h· 4 milestones

Build an accessible search + filter UI that handles every state

The "simple" search box on a product page is where most frontend interviews are actually won or lost. You build one properly, fast, keyboard-driven, accessible, and graceful when things go wrong.

ReactTypeScriptAccessibility (ARIA)DebouncingResponsive designUI state modelingBundle budgetingClient-side error tracking

What you'll build

A debounced search-and-filter interface with explicit loading/empty/error/no-results states, full keyboard navigation, and a clean accessibility audit.

See how we teach, before you sign up

You don't just get code dumped on you. Every starter file and every solution is explained line-by-line, in plain English. Here's one real file from this project:

src/types.tsts
export interface Item {
  id: string;
  name: string;
  category: string;
}

// One status field, never separate isLoading/isError booleans.
export type SearchState =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'error'; message: string }
  | { status: 'empty' } // searched, zero results
  | { status: 'success'; items: Item[] };

Reading this file

  • export interface ItemDefines the single shape every search result must match, so the rest of your code can trust what it gets.
  • export type SearchState =A union of states where each option carries only the data valid for that state, no contradictory combinations possible.
  • { status: 'error'; message: string }The error state must carry a message, the type forces you to handle the why, not just the fact of failure.
  • { status: 'success'; items: Item[] }Only the success state has items, so the compiler stops you reading results when there are none.

The data contract: one Item shape and a discriminated union so impossible states cannot exist.

That's 1 of 7 explained code blocks in this single project.

The build, milestone by milestone

  1. 1

    Model every state

    5 guided steps

    Most search UIs only handle the happy path, so they flicker, show stale data, or go blank on error. Modeling state explicitly is what separates a junior demo from production UI.

  2. 2

    Make it fast & keyboard-first

    5 guided steps

    Typing fires a request per keystroke without debouncing, and out-of-order responses show wrong results. Keyboard users must be able to drive the whole thing without a mouse.

  3. 3

    Pass an a11y audit

    5 guided steps

    Accessibility is a legal and quality bar at real companies, and a combobox done right signals senior frontend skill. Automated tools catch the obvious; a screen-reader pass catches the rest.

  4. 4

    Stay cheap & watch it in the wild

    5 guided steps

    A search box that ships 200KB of fuzzy-match library or throws unhandled errors on every odd query looks fine on your laptop and fails for real users, a tiny cost budget and one error sink catch both before they cost you.

What's inside when you start

3 starter files, ready to clone
4 guided milestones
4 full reference solutions
7 code blocks explained line-by-line
4 "is it working?" checks
4 interview questions it prepares you for

You'll walk away with

A deployed demo with all states (loading/empty/error/results) reachable
A Lighthouse / axe accessibility report at 95+
A short README documenting the state model, keyboard interactions, and the JS bundle budget
Web Vitals logging and an error tracker that captures a real client-side error

This is portfolio-grade. Build it free.

Sign up to unlock every milestone step-by-step, the code skeletons, full reference solutions, and checkable tasks, with your progress saved as you build.

Start building