- Components
Stepper
Where someone is in a flow: numbered steps, the current one marked, each step's state said in words.
npx shadcn add @klarhimmel/stepperWhen to use
Use for
Showing progress through checkout, booking or onboarding.
Not for
A percentage. Use Progress. Switching between views. Use Tabs.
Pairs with
Button, Progress, a heading per step.
Preview
- Dates, Completed
- Guests, Current step
- Payment, Upcoming
- Done, Upcoming
stepper.tsx
import { Theme } from '@/components/klarhimmel/theme/style';
import { Stepper } from '@/components/klarhimmel/ui/stepper';
export default function Example() {
return (
<Theme theme="brand">
<Stepper
aria-label="Booking progress"
current={1}
steps={[{ label: 'Dates' }, { label: 'Guests' }, { label: 'Payment' }]}
/>
</Theme>
);
}Install
Import
import { Stepper } from '@/components/klarhimmel/ui/stepper';- Lands in
- components/klarhimmel/ui/stepper.tsx, plus cn() and the theme item if they are missing. Import theme.css after Tailwind.
- Render in
- Render it inside <Theme>, once near the root of your app. Tokens and fonts are scoped to it, so outside it the component is unstyled.
Examples
Descriptions
- Pay, Current stepCard or invoice
You are on step 3: Pay. Completed steps are buttons.
import { useState } from 'react'; import { Button } from '@/components/klarhimmel/ui/button'; import { Stepper } from '@/components/klarhimmel/ui/stepper'; const steps = [ { label: 'Choose a room', description: 'Seaside, garden or loft' }, { label: 'Your details', description: 'Name and email' }, { label: 'Pay', description: 'Card or invoice' }, ]; export default function StepperDescriptions() { const [current, setCurrent] = useState(2); return ( <div className="flex w-[min(44rem,calc(100cqw-3rem))] flex-col gap-6"> <Stepper aria-label="Checkout" steps={steps} current={current} onStepSelect={setCurrent} /> <p role="status" className="text-kh-small text-kh-muted">You are on step {current + 1}: {steps[current]!.label}. Completed steps are buttons.</p> <div><Button variant="secondary" onClick={() => setCurrent(2)}>Jump to pay</Button></div> </div> ); }Narrow
- Create account, Done
- Add your hotel, You are hereName and address
- Invite the team, Next
In a narrow container the steps run down the side.
import { Stepper } from '@/components/klarhimmel/ui/stepper'; export default function StepperNarrow() { return ( <div className="w-64 rounded-kh-lg border border-kh-line p-4"> <Stepper aria-label="Onboarding" current={1} steps={[{ label: 'Create account' }, { label: 'Add your hotel', description: 'Name and address' }, { label: 'Invite the team' }]} labels={{ complete: 'Done', current: 'You are here', upcoming: 'Next' }} /> <p className="mt-4 text-kh-caption text-kh-muted">In a narrow container the steps run down the side.</p> </div> ); }
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
steps | { label: string; description?: string }[] | - | Required, in order. |
current | number | - | Required. The step the person is on, counting from 0. Earlier steps are complete. |
aria-label | string | - | Required: names the list. |
labels | { complete; current; upcoming } | English words | 'Completed', 'Current step' and 'Upcoming' by default: what assistive tech hears beside each step. Pass them translated. |
onStepSelect | (index: number) => void | - | With it, completed steps are buttons that go back. |
className | string | - | Extra classes, merged after the component's own. |
Accessibility
| Key | Does |
|---|---|
Tab | Reaches completed steps when onStepSelect is given |
Enter / Space | Goes back to the focused completed step |
An ordered list; the current step is aria-current="step" and every step says its state in words, so state is never colour alone.
Accessibility