react-stepper-lite
v1.0.2
Published
Lightweight React stepper component
Maintainers
Readme
react-stepper-lite
Lightweight, production-friendly React stepper.
What you get:
- Good defaults: works out of the box.
- Accessible: roving focus + keyboard navigation.
- Easy to customize: CSS variables,
classNames, and per-step overrides.
Screenshots
Horizontal

Vertical

Install
npm i react-stepper-litePeer deps:
reactreact-dom
Quick start
import { useState } from 'react'
import { Stepper, type StepConfig } from 'react-stepper-lite'
const steps: StepConfig[] = [{ label: 'Login' }, { label: 'Address' }, { label: 'Payment' }]
export function Example() {
const [activeStep, setActiveStep] = useState(0)
return <Stepper steps={steps} activeStep={activeStep} onStepClick={setActiveStep} />
}Stepper is controlled: you own activeStep, and onStepClick is optional.
Examples
1) Basic (non-clickable)
Useful when you have your own “Next” / “Back” buttons and just want a visual indicator.
import { useState } from 'react'
import { Stepper, type StepConfig } from 'react-stepper-lite'
const steps: StepConfig[] = [{ label: 'Login' }, { label: 'Address' }, { label: 'Payment' }]
export function NonClickable() {
const [activeStep, setActiveStep] = useState(0)
return (
<div style={{ display: 'grid', gap: 12 }}>
<Stepper steps={steps} activeStep={activeStep} />
<div style={{ display: 'flex', gap: 8 }}>
<button type="button" onClick={() => setActiveStep((s) => Math.max(0, s - 1))}>
Back
</button>
<button type="button" onClick={() => setActiveStep((s) => Math.min(steps.length, s + 1))}>
Next
</button>
</div>
</div>
)
}2) Clickable steps
When you pass onStepClick, step buttons become interactive (click + Enter/Space).
import { useState } from 'react'
import { Stepper, type StepConfig } from 'react-stepper-lite'
const steps: StepConfig[] = [{ label: 'Login' }, { label: 'Address' }, { label: 'Payment' }]
export function Clickable() {
const [activeStep, setActiveStep] = useState(1)
return <Stepper steps={steps} activeStep={activeStep} onStepClick={setActiveStep} />
}3) Vertical stepper
import { useState } from 'react'
import { Stepper, type StepConfig } from 'react-stepper-lite'
const steps: StepConfig[] = [{ label: 'Account' }, { label: 'Profile' }, { label: 'Done' }]
export function Vertical() {
const [activeStep, setActiveStep] = useState(0)
return (
<Stepper
steps={steps}
activeStep={activeStep}
onStepClick={setActiveStep}
orientation="vertical"
labelPlacement="side"
/>
)
}4) Prev / Next / Skip
“Skipped” is different from “not completed”. Future steps are not completed, but they are not skipped.
import { useMemo, useState } from 'react'
import { Stepper, type StepConfig } from 'react-stepper-lite'
export function SkipExample() {
const steps = useMemo<StepConfig[]>(
() => [{ label: 'Login' }, { label: 'Address' }, { label: 'Payment' }, { label: 'Confirm' }],
[],
)
const [activeStep, setActiveStep] = useState(0)
const [skippedSteps, setSkippedSteps] = useState<number[]>([])
return (
<div style={{ display: 'grid', gap: 12 }}>
<Stepper
steps={steps}
activeStep={activeStep}
skippedSteps={skippedSteps}
labelPlacement="below"
/>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
<button type="button" onClick={() => setActiveStep((s) => Math.max(0, s - 1))}>
Prev
</button>
<button type="button" onClick={() => setActiveStep((s) => Math.min(steps.length, s + 1))}>
Next
</button>
<button
type="button"
onClick={() => {
setSkippedSteps((prev) => (prev.includes(activeStep) ? prev : [...prev, activeStep]))
setActiveStep((s) => Math.min(steps.length, s + 1))
}}
>
Skip
</button>
<button
type="button"
onClick={() => {
setActiveStep(0)
setSkippedSteps([])
}}
>
Reset
</button>
</div>
</div>
)
}5) Icons + per-step overrides
You can set icons and override colors per step.
icon can be:
- a React node
- a string (treated as text)
- a string URL/path (treated as an image)
import { useState } from 'react'
import { Stepper, type StepConfig } from 'react-stepper-lite'
const steps: StepConfig[] = [
{ label: 'Login', icon: '1', color: '#2563eb' },
{ label: 'Address', icon: '2', completedColor: '#16a34a' },
{ label: 'Payment', icon: 'https://raw.githubusercontent.com/prathmesh-jain/react-stepper-lite/main/assets/stepper-horizontal.png' },
{ label: 'Confirm', disabled: true },
]
export function IconsAndOverrides() {
const [activeStep, setActiveStep] = useState(1)
return (
<Stepper
steps={steps}
activeStep={activeStep}
onStepClick={setActiveStep}
completedIcon="✓"
skipIcon="↷"
/>
)
}6) Styling via CSS variables
import { Stepper } from 'react-stepper-lite'
export function ColorsExample({ steps, activeStep }: { steps: { label: string }[]; activeStep: number }) {
return (
<Stepper
steps={steps}
activeStep={activeStep}
style={{
['--stepper-active' as any]: '#7c3aed',
['--stepper-complete' as any]: '#059669',
}}
/>
)
}7) classNames (optional)
Use classNames to attach your own classes to internal elements.
import { useState } from 'react'
import { Stepper, type StepConfig } from 'react-stepper-lite'
const steps: StepConfig[] = [{ label: 'One' }, { label: 'Two' }, { label: 'Three' }]
export function ClassNamesExample() {
const [activeStep, setActiveStep] = useState(0)
return (
<Stepper
steps={steps}
activeStep={activeStep}
onStepClick={setActiveStep}
classNames={{
list: 'myList',
stepButton: 'myStepButton',
activeStep: 'myStep--active',
}}
/>
)
}Styling notes
The default styles are plain CSS and are applied automatically.
If you prefer to bring your own styles:
- use
classNamesto attach your own classes
API (quick reference)
Main exports:
StepperuseStepperState
Most used props:
steps: StepConfig[]activeStep: numberonStepClick?: (index: number) => voidorientation?: 'horizontal' | 'vertical'size?: 'sm' | 'md' | 'lg'labelPlacement?: 'below' | 'side'color?: stringstepColor?: stringcompletedColor?: stringcompletedStepColor?: stringconnectorColor?: stringconnectorCompletedColor?: stringcompletedIcon?: ReactNodeskipIcon?: ReactNodeskippedSteps?: number[]disabled?: booleanclassNames?: StepperClassNames
StepConfig:
label: string(required)icon?: ReactNode | stringcompletedIcon?: ReactNodecompleted?: booleancolor?: stringcompletedColor?: stringskipped?: booleandisabled?: boolean
Accessibility
- Roving focus (Arrow keys)
Home/Endmove to first/last enabled stepEnter/Spaceactivates a step whenonStepClickis provided- Active step uses
aria-current="step"
