useStepState
A flexible React hook for managing step-by-step navigation state with support for custom properties and TypeScript type safety.
Installation
import { useStepState } from "@cfa/react-core";Basic Usage
1. Simple Step Navigation
Pass an array of objects with label properties:
const steps = [ { label: "Personal Information" }, { label: "Account Setup" }, { label: "Verification" }, { label: "Complete" },];
const { steps: stepState, activeStep, incrementStep, decrementStep, goToStep,} = useStepState(steps);
// stepState contains all steps with their current stateconsole.log(stepState);// [// { label: 'Personal Information', state: 'active', step: 1 },// { label: 'Account Setup', state: 'inactive', step: 2 },// { label: 'Verification', state: 'inactive', step: 3 },// { label: 'Complete', state: 'inactive', step: 4 }// ]
// activeStep is the currently active stepconsole.log(activeStep);// { label: 'Personal Information', state: 'active', step: 1 }2. Navigation Functions
const { activeStep, incrementStep, decrementStep, goToStep } = useStepState(steps);
// Move to next stepincrementStep();console.log(activeStep);// { label: 'Account Setup', state: 'active', step: 2 }
// Previous step is now marked as completeconsole.log(stepState[0]);// { label: 'Personal Information', state: 'complete', step: 1 }
// Move back to previous stepdecrementStep();console.log(activeStep);// { label: 'Personal Information', state: 'active', step: 1 }
// Next step is now marked as inactiveconsole.log(stepState[1]);// { label: 'Account Setup', state: 'inactive', step: 2 }
// Go to a specific stepgoToStep(3);console.log(activeStep);// { label: 'Verification', state: 'active', step: 3 }Navigation Behavior:
incrementStep(): Moves forward, marks current step as “complete”decrementStep(): Moves backward, marks current step as “inactive”goToStep(stepNumber: number): Updates step to the passed in step- Automatically prevents going past first/last steps
3. Custom Properties
Add any custom properties to your step objects with full TypeScript support:
interface CustomStep { label: string; id: string; description: string; estimatedTime: number; required: boolean; metadata: { category: "account" | "profile" | "verification"; priority: "high" | "medium" | "low"; };}
const customSteps: CustomStep[] = [ { label: "Create Account", id: "create-account", description: "Set up your basic account information", estimatedTime: 3, required: true, metadata: { category: "account", priority: "high" }, }, { label: "Complete Profile", id: "complete-profile", description: "Add your personal details", estimatedTime: 5, required: true, metadata: { category: "profile", priority: "high" }, },];
const { steps, activeStep } = useStepState(customSteps);
// All custom properties are preserved and accessibleconsole.log(activeStep?.id); // 'create-account'console.log(activeStep?.estimatedTime); // 3console.log(activeStep?.metadata.category); // 'account'console.log(activeStep?.required); // true
// Custom properties remain on all stepssteps.forEach((step) => { console.log( `${step.label}: ${step.estimatedTime} min, ${step.metadata.priority} priority` );});API Reference
Hook Signature
function useStepState<T extends BaseItem>(items: T[]): UseStepStateReturn<T>;Return Value
{ steps: StepsState<T>[]; // All steps with current state activeStep: StepsState<T> | undefined; // Currently active step incrementStep: () => void; // Move to next step decrementStep: () => void; // Move to previous step goToStep: (stepNumber: number) => void // Move to passed in step}Step States
"active": Current step"complete": Completed steps (behind active step)"inactive": Future steps (ahead of active step)
Common Usage Patterns
Progress Tracking
const { steps } = useStepState(mySteps);
const completedSteps = steps.filter((step) => step.state === "complete").length;const totalSteps = steps.length;const progressPercentage = (completedSteps / totalSteps) * 100;Conditional Navigation
const { activeStep, incrementStep } = useStepState(steps);
const handleNext = () => { if (isValidStep(activeStep)) { incrementStep(); }};Finding Specific Steps
const { steps } = useStepState(stepsWithIds);
const currentStepId = steps.find((step) => step.state === "active")?.id;const completedStepIds = steps .filter((step) => step.state === "complete") .map((step) => step.id);