Coding Challenges
React coding interviews usually test how you structure state, handle user input, render lists, manage async flows, and communicate tradeoffs while coding.
Do not silently code for twenty minutes. Explain your plan, name edge cases, build the smallest working version, then improve it.
Challenge 1: Counter with Step
Build a counter with:
- current count
- increment button
- decrement button
- reset button
- step input
- minimum value of zero
Expected behavior:
- increment adds the current step
- decrement subtracts the current step but never goes below zero
- reset sets count to zero
- invalid step values are rejected or corrected
Edge cases:
- empty step input
- negative step
- decimal step
- very large step
Strong solution notes:
- keep
countandstepin state - parse input intentionally
- use functional state updates when next count depends on previous count
Challenge 2: Todo List
Build a todo list with:
- add task
- toggle complete
- delete task
- filter all, active, completed
- count remaining tasks
Follow-up questions:
- Why should task ids be stable?
- Why is
remainingCountderived instead of stored? - How would you persist tasks?
- How would you test this component?
Common mistake:
Mutating the todo object directly:
todo.completed = true;Prefer returning new objects:
setTodos((todos) =>
todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);Challenge 3: Searchable List
Build a list with:
- search input
- case-insensitive filtering
- empty state
- result count
Data:
const users = [
{ id: 1, name: "Ada Lovelace", role: "Engineer" },
{ id: 2, name: "Grace Hopper", role: "Computer Scientist" },
{ id: 3, name: "Katherine Johnson", role: "Mathematician" }
];Expected behavior:
- search by name or role
- trim leading and trailing whitespace
- show all users when query is empty
- show "No results" when nothing matches
Follow-up:
When would you use useMemo here?
Answer:
Only if the list is large or filtering is expensive. For three users, memoization is unnecessary.
Challenge 4: Fetch with Loading and Error
Build a component that fetches posts and renders:
- loading state
- error state
- empty state
- list of posts
- retry button
Requirements:
- no unhandled promise errors
- cleanup or ignore stale requests if the component unmounts
- user-friendly error message
Skeleton:
function PostsList() {
const [posts, setPosts] = useState([]);
const [status, setStatus] = useState("idle");
const [error, setError] = useState(null);
// implement loading here
}Follow-up questions:
- How would this change with TanStack Query?
- How would you test loading and error states?
- What happens if the user clicks retry quickly?
Challenge 5: Tabs Component
Build accessible tabs.
Requirements:
- render tab buttons from data
- show active panel
- support keyboard arrow navigation as an extension
- use stable ids
- keep active tab in state
Data:
const tabs = [
{ id: "overview", label: "Overview", content: "Project summary" },
{ id: "settings", label: "Settings", content: "Project settings" },
{ id: "billing", label: "Billing", content: "Billing details" }
];Accessibility hints:
- use
role="tablist" - use
role="tab" - use
role="tabpanel" - connect tabs and panels with
aria-controlsandaria-labelledby - indicate selected tab with
aria-selected
Challenge 6: Modal Dialog
Build a modal that:
- opens from a button
- closes from a close button
- closes on Escape
- traps focus as an advanced extension
- restores focus to the opener as an advanced extension
Common mistakes:
- closing only with a mouse
- leaving background content focusable
- not cleaning up keydown listeners
- rendering modal content but hiding it only visually
Challenge 7: Cart Reducer
Implement a cart reducer.
Actions:
add_item
remove_item
set_quantity
clear_cartRules:
- adding an existing item increases quantity
- quantity must be at least one
- removing deletes the item
- total is derived outside the reducer
Follow-up:
Why is a reducer useful here?
Answer:
It centralizes cart state transitions and makes action behavior easier to test.
During a React coding interview, what is usually the best first step?
Interview Strategy
Use this flow:
- Repeat the requirements.
- Ask about edge cases.
- Define state shape.
- Build the simplest working UI.
- Handle validation and empty states.
- Refactor repeated logic.
- Explain tests and tradeoffs.
Common Mistakes
- Overengineering before the base behavior works.
- Forgetting empty and error states.
- Mutating arrays or objects in state.
- Using index keys in interactive lists.
- Not explaining decisions.
- Ignoring accessibility for tabs, forms, and modals.
- Adding
useMemobefore identifying a performance problem.
Practice Plan
Pick three challenges and solve each twice:
- first version: working in 20 minutes
- second version: cleaner architecture and tests
After each attempt, write:
- what state you used
- what edge case you missed
- what you would improve with more time
Recap
React coding challenges reward clear state design, incremental delivery, edge-case awareness, and communication. Build the core behavior first, then polish.