Build a frontend app from scratch — tested code quality, scalability, & component design.
A take-home/live exercise judging structure, not just 'does it work'. Set up tooling, organize by feature, separate data/logic/presentation, build small composable components, manage state deliberately, handle loading/error/empty states, write meaningful tests, and document decisions.
This is an open exercise where the interviewer judges how you build, not just the output. Treat the unstated requirements (quality, scalability, component design) as the actual rubric.
1. Set up the foundation
- Modern toolchain: Vite + React + TypeScript, ESLint + Prettier, a test runner (Vitest + RTL).
- A clear
README— how to run, decisions made, tradeoffs, what you'd do with more time.
2. Structure for scale — feature-first
src/
features/<feature>/ components, hooks, api, types
shared/ui/ reusable primitives
shared/lib/ utils
app/ routing, providersNot type-first folders. The reviewer should see where things would go as the app grows.
3. Separate concerns
- Data/logic in custom hooks (
useTodos,useFilters) — fetching, state, derived values. - Presentational components — pure, props in / events out, no fetching.
- Container/page — composition only.
This separation is the "scalability" and "component design" they're grading.
4. Component design
- Small, single-responsibility, composable.
- Well-typed props; controlled/uncontrolled where it matters.
- Extract shared primitives (
Button,Input) instead of repeating. - Composition over giant prop objects.
5. State, deliberately
- Local state by default; lift only when shared.
- Server state via React Query/SWR if there's fetching — don't hand-roll
useEffectcaching. - Don't reach for Redux on a small exercise; show judgment.
6. Handle the real states
Loading, error, empty, and success — every async surface. Empty and error states are exactly what juniors skip and reviewers look for.
7. Test what matters
- A few integration tests (RTL) on key user flows — render, interact, assert behavior.
- Unit-test non-trivial logic (the hooks, utils).
- Quality over coverage % — show you know what to test.
8. Polish & communicate
- Accessibility basics — semantic HTML, labels, keyboard.
- Responsive layout.
- Clean commit history.
- In the README: call out tradeoffs and "with more time I'd add X" — this shows senior judgment even when you couldn't do everything.
The mental model
They gave a vague prompt on purpose. The signal is: do you impose structure, separation, and quality without being told to? Narrate your decisions as you go (in a live setting) or in the README (take-home) — the reasoning is half the score.
Follow-up questions
- •How do you decide your folder structure on a greenfield app?
- •What would you test, and why those things specifically?
- •When would you NOT reach for a state management library here?
- •How do you communicate tradeoffs you made under time pressure?
Common mistakes
- •Optimizing only for 'it works' and ignoring structure, tests, and edge states.
- •Type-first folders that won't scale.
- •Skipping empty/error/loading states.
- •Over-engineering — Redux, abstractions, and patterns a small app doesn't need.
- •No README explaining decisions and tradeoffs.
Performance considerations
- •Show awareness without gold-plating: code-split routes, memoize where it matters, virtualize a long list if the data warrants it. Mention what you'd optimize at scale rather than prematurely optimizing a small exercise.
Edge cases
- •Running out of time — prioritize structure + core flow + README notes.
- •Ambiguous requirements — state your assumptions explicitly.
- •Scope creep — show you can cut deliberately.
Real-world examples
- •A take-home todo/kanban/dashboard app where the score is structure, separation, tests, and edge-state handling.
- •A live build where narrating 'I'll separate the data hook from the view so this scales' is the signal.