My first stepper

Build a minimal stepper using defineStepper and useStepper

This page walks you through building a minimal stepper without primitives (no Stepper.List, Stepper.Item, Stepper.Trigger, etc.) and without Scoped or Stepper.Root. You only need defineStepper and useStepper. When you call useStepper() directly in a component, the hook owns the stepper state—no provider required.

Define your steps

defineStepper is the entry point. You pass one object per step (each with at least a unique id) and get back a typed stepper: useStepper, and optionally Scoped, Stepper (primitives). For this example we only use useStepper.

Here we define four steps: Name, Email, Confirm, and Done. You can add any extra fields (title, description, etc.) for your UI.

import { defineStepper } from "@stepperize/react";

const { useStepper } = defineStepper(
  { id: "name", title: "Name" },
  { id: "email", title: "Email" },
  { id: "confirm", title: "Confirm" },
  { id: "done", title: "Done" },
);

Use the hook in your component

useStepper returns the stepper instance. Call it inside the component that renders your UI (not at module top level), because the hook uses React state. From the returned stepper you get:

  • statestate.current (current step object), state.isFirst, state.isLast
  • flowflow.switch({ ... }) to render content per step (one branch per step id)
  • navigationnavigation.next(), navigation.prev(), navigation.goTo(id), navigation.reset()
function MyStepper() {
  const stepper = useStepper();
  return (
    <>
      <p>Step: {stepper.state.current.data.title}</p>
      <div>
        {stepper.flow.switch({
          name: () => <p>What is your name?</p>,
          email: () => <p>What is your email?</p>,
          confirm: () => <p>Confirm.</p>,
          done: () => <p>All done!</p>,
        })}
      </div>
      <div>
        {!stepper.state.isFirst && (
          <button onClick={() => stepper.navigation.prev()}>Back</button>
        )}
        {stepper.state.isLast ? (
          <button onClick={() => stepper.navigation.reset()}>Reset</button>
        ) : (
          <button onClick={() => stepper.navigation.next()}>Next</button>
        )}
      </div>
    </>
  );
}

Full example

import * as React from "react";
import {  } from "@stepperize/react";

const {  } = (
  { : "name", : "Name" },
  { : "email", : "Email" },
  { : "confirm", : "Confirm" },
  { : "done", : "Done" },
);

export function () {
  const  = ();
  return (
    <>
      <>Step: <>{....}</></>
      <>
        {..({
          : () => <>What is your name?</>,
          : () => <>What is your email?</>,
          : () => <>Please confirm your details.</>,
          : () => <>All done!</>,
        })}
      </>
      <>
        {.. ? (
          < ={() => ..()}>Reset</>
        ) : (
          <>
            < ={() => ..()} ={..}>Back</>
            < ={() => ..()}>Next</>
          </>
        )}
      </>
    </>
  );
}
  • defineStepper — defines your steps and returns useStepper (and optionally Scoped, Stepper).
  • useStepper() — returns the stepper instance; when called in a component with no provider, that component owns the stepper state.
  • No provider is required: you don't need Scoped or Stepper.Root for this pattern.

Result

Step: Name

What is your name?

Edit on GitHub

Last updated on

On this page