Basic
Step-by-step guides to build horizontal, vertical, and custom steppers with minimal code.
Horizontal Stepper
A horizontal stepper shows steps in a row. Here’s how to build one from scratch.
Define your steps
Use defineStepper with one object per step. Each step needs a unique id; add any extra fields (e.g. title) for your UI.
import { } from "@stepperize/react";
const { , } = (
{ : "account", : "Account" },
{ : "profile", : "Profile" },
{ : "done", : "Done" }
);Wrap with Stepper.Root
Stepper.Root provides the stepper context (it uses Scoped internally) and passes the stepper to your render function. Use orientation="horizontal" (default) for a horizontal layout.
import React from "react";
import { } from "@stepperize/react";
const { } = (
{ : "account", : "Account" },
{ : "profile", : "Profile" },
{ : "done", : "Done" }
);
function () {
return (
<.>
{({ }) => (
<>
{/* list and content go here */}
</>
)}
</.>
);
}Render the step list
Map over stepper.state.all and render one Stepper.Item per step. Each item needs a Trigger (and optionally Title, Indicator, Separator).
import React from "react";
import { } from "@stepperize/react";
const { } = (
{ : "account", : "Account" },
{ : "profile", : "Profile" },
{ : "done", : "Done" }
);
function () {
return (
<.>
{({ }) => (
<.>
{...(() => (
<React. ={.}>
<. ={.}>
<.>
<. />
<.>{.}</.>
</.>
<. />
</.>
</React.>
))}
</.>
)}
</.>
);
}Show content per step
Use Stepper.Content with a step prop so each panel is visible only when that step is current.
import React from "react";
import { } from "@stepperize/react";
const { } = (
{ : "account", : "Account" },
{ : "profile", : "Profile" },
{ : "done", : "Done" }
);
function () {
return (
<.>
{({ }) => (
<>
<. ="account"><>Account form</></.>
<. ="profile"><>Profile form</></.>
<. ="done"><>All done!</></.>
</>
)}
</.>
);
}Add Prev / Next buttons
Put Stepper.Prev and Stepper.Next inside Stepper.Actions. They call navigation.prev() and navigation.next() and are disabled on first/last step automatically.
Live preview
- →→
Account form
Full example
import React from "react";
import { } from "@stepperize/react";
const { } = (
{ : "account", : "Account" },
{ : "profile", : "Profile" },
{ : "done", : "Done" }
);
function ({ }: { : React. }) {
return (
<. ="border border-gray-300 bg-white px-2 py-1 text-sm data-[status=active]:bg-blue-100 dark:data-[status=active]:bg-blue-900/40">
{}
</.>
);
}
export function () {
return (
<.>
{({ }) => (
<>
<. ="m-0 flex list-none flex-wrap gap-2 p-0">
{...(() => (
<React. ={.}>
<. ={.}>
<>
<. ={() => < {...}>{.}</>} />
</>
</.>
{. !== "done" && < ="self-center text-gray-400">→</>}
</React.>
))}
</.>
< ="mt-4 min-h-12">
<. ="account"><>Account form</></.>
<. ="profile"><>Profile form</></.>
<. ="done"><>All done!</></.>
</>
< ="mt-4 flex flex-wrap gap-2">
{.. ? (
< ="button" ={() => ..()}>
Reset
</>
) : (
<>
<.>Previous</.>
<.>Next</.>
</>
)}
</>
</>
)}
</.>
);
}Vertical Stepper
Same structure as the horizontal stepper; only the orientation changes. Pass orientation="vertical" to Stepper.Root and Stepper.List.
Use vertical orientation
Pass orientation="vertical" to Stepper.Root and Stepper.List. Use a custom separator (e.g. a line) between items since Stepper.Separator supports vertical layout.
Live preview
Content for Step 1
Full example
import React from "react";
import { } from "@stepperize/react";
const { } = (
{ : "one", : "Step 1" },
{ : "two", : "Step 2" },
{ : "three", : "Step 3" }
);
function ({ }: { : React. }) {
return (
<. ="border border-gray-300 bg-white px-2 py-1 text-sm data-[status=active]:bg-blue-100 dark:data-[status=active]:bg-blue-900/40">
{}
</.>
);
}
function () {
return < ="ml-3 h-3 w-px bg-gray-300 dark:bg-gray-600" />;
}
export function () {
return (
<. ="vertical">
{({ }) => (
<>
<.
="vertical"
="m-0 flex w-fit list-none flex-col items-stretch gap-0 p-0"
>
{...((, ) => (
<React. ={.}>
<. ={.}>
<>
<. ={() => < {...}>{.}</>} />
</>
</.>
{ < ... - 1 && < />}
</React.>
))}
</.>
< ="mt-4 min-h-10">
{...(() => (
<. ={.} ={.}>
<>Content for {.}</>
</.>
))}
</>
< ="mt-4 flex flex-wrap gap-2">
{.. ? (
< ="button" ={() => ..()}>
Reset
</>
) : (
<>
<.>Back</.>
<.>Continue</.>
</>
)}
</>
</>
)}
</.>
);
}Custom step indicator
By default, Stepper.Indicator has no built-in content. You control what it shows via children or the render prop. For example, show the step index (1, 2, 3) using useStepItemContext() from the primitives entry.
Custom indicator with step index
import React from "react";
import { } from "@stepperize/react";
import { } from "@stepperize/react/primitives";
const { } = (
{ : "a", : "First" },
{ : "b", : "Second" },
{ : "c", : "Third" }
);
function () {
const = ();
return <>{. + 1}</>;
}
function () {
return (
<.>
{({ }) => (
<.>
{...(() => (
<React. ={.}>
<. ={.}>
<.>
<.>
< />
</.>
<.>{.}</.>
</.>
<. />
</.>
</React.>
))}
</.>
)}
</.>
);
}Alternative: render prop on Indicator
You can also use the render prop to receive DOM props and render a custom element (e.g. for styling the “circle” later).
import React from "react";
import { } from "@stepperize/react";
import { } from "@stepperize/react/primitives";
const { } = (
{ : "x", : "Step X" },
{ : "y", : "Step Y" }
);
function () {
const = ();
return (
<.
={() => (
< {...}>{. + 1}</>
)}
/>
);
}
// Use inside Stepper.Item:
// <Stepper.Trigger>
// <CustomIndicator />
// <Stepper.Title>{step.title}</Stepper.Title>
// </Stepper.Trigger>Live preview
- →→
First step content
Full example
import React from "react";
import { } from "@stepperize/react";
import { } from "@stepperize/react/primitives";
const { } = (
{ : "a", : "First" },
{ : "b", : "Second" },
{ : "c", : "Third" }
);
function () {
const = ();
return <>{. + 1}</>;
}
function ({ }: { : React. }) {
return (
<. ="rounded-full border border-gray-300 bg-white px-2 py-1 text-sm data-[status=active]:bg-blue-100 dark:data-[status=active]:bg-blue-900/40">
{}
</.>
);
}
export function () {
return (
<.>
{({ }) => (
<>
<. ="m-0 flex list-none flex-wrap gap-2 p-0">
{...(() => (
<React. ={.}>
<. ={.}>
<>
<. ="inline-flex size-4 items-center justify-center rounded-full bg-inherit text-xs font-semibold">
< />
</.>
<. ={() => < {...}>{.}</>} />
</>
</.>
{. !== "c" && < ="self-center text-gray-400">→</>}
</React.>
))}
</.>
< ="mt-4 min-h-10">
<. ="a"><>First step content</></.>
<. ="b"><>Second step content</></.>
<. ="c"><>Third step content</></.>
</>
< ="mt-4 flex flex-wrap gap-2">
{.. ? (
< ="button" ={() => ..()}>
Reset
</>
) : (
<>
<.>Previous</.>
<.>Next</.>
</>
)}
</>
</>
)}
</.>
);
}Usage tips
- Use
stepper.flow.switch({ stepId: () => <Content /> })to render content per step, orStepper.Content step="stepId"for a declarative panel per step. - Use
stepper.navigation.next(),prev(), andgoTo(id)to change steps;Stepper.PrevandStepper.Nextdo this for you when used insideStepper.Actions. - Add validation between steps with
stepper.lifecycle.onBeforeTransition; returnfalse(or a promise resolving tofalse) to cancel the transition. - Style with CSS or Tailwind using
data-component,data-status, anddata-orientationon the primitives.
Last updated on