Build a complete frontend application that consumes APIs, manages state, and is fully responsive.
An open-ended take-home/architecture prompt. Walk the structure: folder/component architecture, a data layer (React Query for server state) vs UI state, routing, all async UI states, responsive design, error boundaries, accessibility, testing, and performance. Show breadth and judgment, not one feature.
This is deliberately open-ended — they're grading architecture and breadth of judgment, not a single clever feature. Walk a structure.
1. Project structure
- Feature-based folders (
features/cart,features/products) over type-based (components/,utils/) once it grows. - A clear split: UI components (dumb, presentational) vs container/feature logic vs shared primitives.
- Consistent naming, colocation of component + styles + tests.
2. Data layer — separate server state from client state
- Server state → React Query / SWR / RTK Query: caching, deduping, refetch, loading/error states, optimistic updates. Don't hand-roll this.
- Client/UI state →
useState/useReducerlocally; Context or Zustand for genuinely global UI state (theme, auth). - An API layer — a typed client wrapping
fetch, centralizing base URL, auth headers, error normalization.
3. Routing
- A router (React Router / Next.js), route-based code splitting (
lazy+Suspense), protected routes for auth.
4. Every async UI state
The mark of a complete app: each data-driven view handles loading, empty, error, and success — skeletons, empty states, retry on error. Not just the happy path.
5. Responsive & accessible
- Mobile-first CSS, fluid layouts (fl/grid,
clamp()), tested across breakpoints. - Semantic HTML, keyboard navigation, focus management, labels, contrast,
aria-livefor dynamic updates.
6. Resilience
- Error boundaries so one crash doesn't white-screen the app.
- Graceful network-failure handling, retries, offline awareness.
7. Quality & tooling
- Testing — unit (logic), component (Testing Library), a few E2E (Playwright) for critical flows.
- TypeScript, ESLint/Prettier, CI running lint + test + build.
- Env-based config, no secrets in the bundle.
8. Performance
- Code splitting, memoization where the profiler says so, image optimization, list virtualization for big lists, debounced inputs. Lighthouse / Core Web Vitals checked.
How to actually answer it live
Don't dump all of the above flatly. Ask clarifying questions (what domain? scale? team size?), then pick a vertical slice — e.g. a product list with search, detail, and cart — and reason through that end-to-end, naming where each concern above plugs in. Depth on one slice + awareness of the rest beats a shallow checklist.
The framing
"It's an architecture question, so I'd structure it: feature-based folders; a data layer that separates server state — React Query for caching/refetch/loading — from client state; routing with code splitting and protected routes; every async view handling loading/empty/error/success; responsive mobile-first and accessible markup; error boundaries for resilience; testing and CI; and performance via splitting, virtualization, and memoization where profiled. Live, I'd scope it to one vertical slice and reason through that deeply rather than listing everything shallowly."
Follow-up questions
- •How do you separate server state from client state?
- •Why use React Query instead of fetching in useEffect?
- •How would you structure folders as the app grows?
- •Which parts would you test, and with what?
Common mistakes
- •Only building the happy path — no loading/empty/error states.
- •Hand-rolling caching/refetching instead of using a query library.
- •Type-based folders that don't scale; no clear component boundaries.
- •Skipping accessibility and responsive design entirely.
- •Listing every concern shallowly instead of going deep on a slice.
Performance considerations
- •Code splitting per route, list virtualization for large data, debounced search, image optimization, and profiling-driven memoization. Track Core Web Vitals; keep the initial bundle small for TTI.
Edge cases
- •Slow or failing API — needs retries, skeletons, error boundaries.
- •Empty datasets and very large datasets (virtualization).
- •Offline / flaky network.
- •Auth expiry mid-session.
Real-world examples
- •A typical take-home: product catalog with search, detail pages, and a persistent cart.
- •Dashboards combining React Query for data with Zustand/Context for UI state.