One Stepper, used uncontrolled and controlled
Tickets is uncontrolled: it counts by itself and only reports. Guests is controlled: the third click asks for 5, the parent refuses, and the screen stays at 4, because the screen always shows the parent's value.
A component's props are its API: name them like the platform (onChange, disabled), support both controlled (value + onChange) and uncontrolled (defaultValue) use, prefer composition with children over piles of configuration props, express looks as variant/size, and leave escape hatches: className, ...rest and ref.
Change the code and press Run (Ctrl+Enter). Predict what will happen first, then break it on purpose and read what changes. Your edits are saved and match the lesson page.
Ready for more? This phase has 5 hands-on exercises with automatic checks.
Practice questions
Write the code in the editor, run it, then open the model answer to compare.
Write a Toggle (a switch button) that supports checked, defaultChecked and onCheckedChange, using useControllableState.
Turn this configuration API into a composition API: <Alert title="Saved" message="Your draft was saved." actionLabel="Undo" onAction={undo} />.
Explain it without notes
How would you design a component that can be both controlled and uncontrolled?
What does "composition over configuration" mean for component APIs? Give an example.
What is the difference between an as prop and the asChild pattern?
Which escape hatches should a design-system component offer, and why?
Preview
Console
Nothing logged yet.Expected console output
Tickets changed to 2
Tickets changed to 3
Guests asked for 3
Guests asked for 4
Guests asked for 5
Screen shows Tickets = 3 and Guests = 4