Build a multi-step form wizard
Build a three-step onboarding wizard: Account (email, password), Profile (name, role), Review (read-back + Submit).
The Next button advances only when the current step is valid. The Back button goes to the previous step without re-validating. State is preserved when navigating back.
Submit on the Review step calls the local handler and shows a confirmation.
Requirements
- An element `<p data-testid="step-indicator">Step N of 3</p>` always reflects the current step (N is 1-indexed).
- Step 1 renders `<input data-testid="email">` and `<input data-testid="password">`. Email must contain an "@" character; password must be ≥ 6 characters. Next is enabled only when both are valid.
- Step 2 renders `<input data-testid="name">` and `<input data-testid="role">`. Both must be non-empty.
- Step 3 renders `<p data-testid="review-email">`, `<p data-testid="review-name">`, `<p data-testid="review-role">` showing the committed values, and a `<button data-testid="submit">Submit</button>`.
- The Next button is `<button data-testid="next">Next</button>` with `disabled={!valid}`.
- The Back button is `<button data-testid="back">Back</button>`, hidden on step 1.
- On submit, show `<p data-testid="done">Welcome, {name}!</p>` and hide the form.
Where it's been asked
- Stripe
- Shopify
- Atlassian
From public interview reports — a build very like this one has shown up in a round at these companies. Not an exhaustive list.
Stuck? The react course covers the ideas this problem is built on.
import { useState } from "react"; export default function App() { const [step, setStep] = useState(1); const [form, setForm] = useState({ email: "", password: "", name: "", role: "" }); const [submitted, setSubmitted] = useState(false); // TODO: compute validity per step; wire Next (disabled when invalid), // Back (hidden on step 1), and the review step. if (submitted) { return <p data-testid="done">Welcome, {form.name}!</p>; } return ( <div style={{ fontFamily: "sans-serif", padding: 16, maxWidth: 320 }}> <p data-testid="step-indicator">Step {step} of 3</p> {/* TODO: render each step's inputs */} <div style={{ marginTop: 16 }}> {step > 1 ? <button data-testid="back">Back</button> : null} {step < 3 ? <button data-testid="next">Next</button> : null} {step === 3 ? <button data-testid="submit">Submit</button> : null} </div> </div> ); }
Ready to check it?
5 tests run against your rendered component, right here in your browser. Sign in to claim the XP when you pass.
Need a nudge?
Reveal a conceptual hint or the reference solution. Both were written and reviewed with the problem — no runtime magic.
Discussion
Sign in to postNo comments yet. Be the first to say something.