Constimport { Stepper } from "./Stepper";
const App = () => (
<Stepper initialStep={0} maxStepIndex={2}>
<StepOne />
<StepTwo />
<StepThree />
</Stepper>
);
initialStep is clamped to be within [0, maxStepIndex]maxStepIndex changes, currentStep is revalidated to ensure it's still within boundsexport const Stepper: FC<
PropsWithChildren<{
initialStep?: number
maxStepIndex: number
}>
> = ({children, maxStepIndex, initialStep = 0}) => {
const [currentStep, setStep] = useState(verifyStep(initialStep))
const [canProceedState, setCanProceedState] = useState<{ [key in number]: boolean }>({})
useEffect(() => {
setStep((s) => verifyStep(s));
}, [maxStepIndex]);
function verifyStep(step: number): number {
return step < 0 ? 0 : Math.min(step, maxStepIndex)
}
const value: StepperContextType = {
currentStep,
next: () => setStep((prev) => verifyStep(prev + 1)),
prev: () => setStep((prev) => verifyStep(prev - 1)),
goTo: (step) => setStep(verifyStep(step)),
setCanProceed: (step, canProceed) => setCanProceedState(prev => {
return {
...prev,
[step]: canProceed
}
}),
canProceed: (step) => typeof canProceedState[step] !== undefined ? canProceedState[step] : true
}
return (
<StepperContext.Provider value={value}>
{children}
</StepperContext.Provider>
)
}
Stepper component provides context for managing current step state in a multistep workflow (wizard, form, tutorial, etc.).
It exposes
currentStepand methods to navigate steps:next(): go to the next step (not beyondmaxStepIndex)prev(): go to the previous step (not below 0)goTo(step: number): jump to a specific step index, clamped to [0, maxStepIndex]The component uses
React.Contextto share the current step and navigation methods with nested components.Wrap your step components inside Stepper to access the step context via
useContext(StepperContext).