Steps
freeSteps track progress through a multi-stage flow like checkout or onboarding.
Preview
Dark
Account
Shipping
Payment
Review
import Steps from '@/components/ui/Steps';
export default function UsageDemo() {
return (
<div className="w-full">
<Steps current={1}>
<Steps.Item title="Account" />
<Steps.Item title="Shipping" />
<Steps.Item title="Payment" />
<Steps.Item title="Review" />
</Steps>
</div>
);
}Installation
Add this component with the NateUI CLI.
npx nateui@latest add StepsExamples
Basic
Preview
Dark
import Steps from '@/components/ui/Steps';
export default function BasicDemo() {
return (
<div className="w-full">
<Steps current={2}>
<Steps.Item />
<Steps.Item />
<Steps.Item />
<Steps.Item />
</Steps>
</div>
);
}Title
Preview
Dark
Cart
Address
Delivery
Confirm
import Steps from '@/components/ui/Steps';
export default function TitleDemo() {
return (
<div className="w-full">
<Steps current={2}>
<Steps.Item title="Cart" />
<Steps.Item title="Address" />
<Steps.Item title="Delivery" />
<Steps.Item title="Confirm" />
</Steps>
</div>
);
}Custom Icon
Preview
Dark
Sign in
In review
Documents
Approved
import Steps from '@/components/ui/Steps';
import Spinner from '@/components/ui/Spinner';
import { PiFileMagnifyingGlass, PiSealCheck, PiSignIn } from 'react-icons/pi'
export default function CustomIconDemo() {
return (
<div className="w-full">
<Steps current={1}>
<Steps.Item title="Sign in" customIcon={<PiSignIn />} />
<Steps.Item title="In review" customIcon={<Spinner size={16} />} />
<Steps.Item title="Documents" customIcon={<PiFileMagnifyingGlass />} />
<Steps.Item title="Approved" customIcon={<PiSealCheck />} />
</Steps>
</div>
);
}Error
Preview
Dark
Details
Payment
Review
Done
import Steps from '@/components/ui/Steps';
export default function ErrorDemo() {
return (
<div className="w-full">
<Steps current={2} status="error">
<Steps.Item title="Details" />
<Steps.Item title="Payment" />
<Steps.Item title="Review" />
<Steps.Item title="Done" />
</Steps>
</div>
);
}Vertical
Preview
Dark
Account
Shipping
Payment
Review
import Steps from '@/components/ui/Steps';
export default function VerticalDemo() {
return (
<Steps vertical current={1}>
<Steps.Item title="Account" />
<Steps.Item title="Shipping" />
<Steps.Item title="Payment" />
<Steps.Item title="Review" />
</Steps>
);
}Description
Preview
Dark
AccountCreate your workspace login
TeamInvite the people you work with
BillingAdd a payment method
LaunchPublish your first project
import Steps from '@/components/ui/Steps';
export default function DescriptionDemo() {
return (
<Steps vertical current={1}>
<Steps.Item
title="Account"
description="Create your workspace login"
/>
<Steps.Item
title="Team"
description="Invite the people you work with"
/>
<Steps.Item
title="Billing"
description="Add a payment method"
/>
<Steps.Item
title="Launch"
description="Publish your first project"
/>
</Steps>
);
}Controlled
Preview
Dark
Account
Shipping
Payment
Review
Step 1 of 4 — Account
import { useState } from 'react';
import Steps from '@/components/ui/Steps';
import Button from '@/components/ui/Button';
const LABELS = ['Account', 'Shipping', 'Payment', 'Review'];
export default function ControlledDemo() {
const [current, setCurrent] = useState(0);
const last = LABELS.length - 1;
const goTo = (next: number) => {
setCurrent(Math.min(Math.max(next, 0), last));
};
return (
<div className="grid w-full gap-8">
<Steps current={current} onChange={goTo}>
{LABELS.map((label) => (
<Steps.Item key={label} title={label} />
))}
</Steps>
<div className="flex items-center justify-between">
<span className="text-sm text-muted-foreground">
Step {current + 1} of {LABELS.length} — {LABELS[current]}
</span>
<div className="flex gap-2">
<Button
disabled={current === 0}
onClick={() => goTo(current - 1)}
>
Previous
</Button>
<Button
variant="solid"
disabled={current === last}
onClick={() => goTo(current + 1)}
>
Next
</Button>
</div>
</div>
</div>
);
}API
Steps is a compound component. Steps owns the current index and derives each item's status from it, while Steps.Item renders one stage and can override its own status, icon, title, and description.
Steps
| Prop | Description | Type | Default |
|---|---|---|---|
current | Zero-based index of the active step. Earlier steps render as complete, later steps as pending. | number | 0 |
status | Status applied to the active step. Use 'error' to flag a failed step in the flow. | StepStatus | 'in-progress' |
vertical | Stack steps vertically instead of in a horizontal row. | boolean | false |
onChange | Fired with a step index when a step is clicked. Providing it makes steps clickable. | (index: number) => void | - |
className | Extra classes for the steps container. | string | - |
Steps.Item
| Prop | Description | Type | Default |
|---|---|---|---|
title | Step label shown beside or below the indicator. | string | ReactNode | - |
description | Supporting text under the title. Renders only when Steps is vertical. | string | ReactNode | - |
customIcon | Node rendered inside the indicator in place of the check, cross, or step number. | string | ReactNode | - |
status | Overrides the status derived from current for this step. | StepStatus | - |
className | Extra classes for the step item. | string | - |
Types
type StepStatus = 'complete' | 'pending' | 'in-progress' | 'error'