Stepperize provides three primary ways to manage state depending on your UI architecture:
- Local State (
useStepper()): Best for compact wizards where the content, actions, and progress live within a single component. If called outside a Provider or Stepper.Root, it creates a new local instance. - Shared State (
Provider): Best when the UI is split across multiple components. By wrapping descendants in a generated checkout.Provider, any descendant calling checkout.useStepper() will read the shared instance from context instead of creating a new one. - Controlled State: Best when an external source (Router, URL, Store, or Server) owns the source of truth. You can pass options like
step, onStepChange, data, onDataChange, completed, and onCompletedChange to useStepper() to sync the stepper with external state.
import { defineStepper } from "@stepperize/react";
const checkout = defineStepper([
{ id: "shipping", title: "Shipping" },
{ id: "payment", title: "Payment" },
{ id: "review", title: "Review" },
]);
// 1. Local
function Checkout() {
const stepper = checkout.useStepper();
return <Panel stepper={stepper} />;
}
// 2. Provider
function CheckoutShell() {
return (
<checkout.Provider defaultStep="shipping">
<Sidebar />
<Panel />
</checkout.Provider>
);
}
// 3. Controlled
const stepper = checkout.useStepper({
step,
onStepChange: setStep,
data: values,
onDataChange: setValues,
completed,
onCompletedChange: setCompleted,
});