# useStep > 1-indexed step counter for wizards and steppers. - Category: State - Package: `hookli` (install with `npm i hookli`) - Docs: https://hookli.vercel.app/docs/use-step ## Signature ```ts useStep(maxStep: number): [number, UseStepActions] ``` ## Parameters - `maxStep`: `number` — The highest reachable step (inclusive). Steps run from 1 to maxStep. ## Returns - `[0] step`: `number` — The current step, 1-indexed. - `[1] actions`: `UseStepActions` — Controls for moving between steps — see below. ## Types ### UseStepActions The second tuple element — the stepper controls. - `goToNextStep`: `() => void` — Advances to the next step; a no-op at maxStep. - `goToPrevStep`: `() => void` — Goes back one step; a no-op at step 1. - `reset`: `() => void` — Resets back to step 1. - `canGoToNextStep`: `boolean` — Whether a next step is available. - `canGoToPrevStep`: `boolean` — Whether a previous step is available. - `setStep`: `Dispatch>` — Sets the step directly (1-indexed); throws if outside the 1..maxStep range. ## Usage ```tsx import { useStep } from "hookli"; export function Demo() { const [step, { goToNextStep, goToPrevStep, canGoToNextStep, canGoToPrevStep, reset }] = useStep(4); return (

Step {step} of 4

); } ``` ## Source `src/hooks/use-step/use-step.ts` ```ts import { Dispatch, SetStateAction, useCallback, useMemo, useState } from "react"; export interface UseStepActions { goToNextStep: () => void; goToPrevStep: () => void; reset: () => void; canGoToNextStep: boolean; canGoToPrevStep: boolean; setStep: Dispatch>; } export const useStep = (maxStep: number): [number, UseStepActions] => { const [currentStep, setCurrentStep] = useState(1); const canGoToNextStep = useMemo( () => currentStep + 1 <= maxStep, [currentStep, maxStep], ); const canGoToPrevStep = useMemo(() => currentStep - 1 >= 1, [currentStep]); const setStep = useCallback>>( (step) => { setCurrentStep((prev) => { const newStep = step instanceof Function ? step(prev) : step; if (newStep >= 1 && newStep <= maxStep) { return newStep; } throw new Error("Step not valid"); }); }, [maxStep], ); const goToNextStep = useCallback(() => { setCurrentStep((prev) => (prev + 1 <= maxStep ? prev + 1 : prev)); }, [maxStep]); const goToPrevStep = useCallback(() => { setCurrentStep((prev) => (prev - 1 >= 1 ? prev - 1 : prev)); }, []); const reset = useCallback(() => { setCurrentStep(1); }, []); return [ currentStep, { goToNextStep, goToPrevStep, canGoToNextStep, canGoToPrevStep, setStep, reset }, ]; }; ```