Components
Navigation
Stepper

Stepper

Use StepperContext to build consistent, accessible interfaces aligned with the shared design system.

Installation

1. Copy the source code:

  • Source in this monorepo: packages/ui/src/components/stepper.tsx
  • Place in your project: components/ui/stepper.tsx
  • Required utility: lib/utils.ts (for cn helper)

2. Update the import paths to match your project structure.


Usage

import { defineStepper } from "@hoag/ui/components/stepper";
 
const steps = [
  { id: "account", title: "Account" },
  { id: "workspace", title: "Workspace" },
  { id: "done", title: "Done" },
];
 
const {
  StepperProvider,
  StepperNavigation,
  StepperStep,
  StepperTitle,
  StepperPanel,
  StepperControls,
  useStepper,
} = defineStepper(...steps);
 
function WizardBody() {
  const { methods } = useStepper();
 
  return (
    <StepperPanel>
      <p className="text-sm">Current step: {methods.currentStepData?.title}</p>
      <StepperControls>
        <button onClick={methods.prev} disabled={methods.isFirst}>
          Back
        </button>
        <button onClick={methods.next} disabled={methods.isLast}>
          Next
        </button>
      </StepperControls>
    </StepperPanel>
  );
}
 
export default function Demo() {
  return (
    <StepperProvider>
      <StepperNavigation>
        {steps.map((step) => (
          <StepperStep key={step.id} of={step}>
            <StepperTitle>{step.title}</StepperTitle>
          </StepperStep>
        ))}
      </StepperNavigation>
      <WizardBody />
    </StepperProvider>
  );
}

Import

import {
  StepperContext,
  defineStepper,
  useStepper,
} from "@hoag/ui/components/stepper";

Basic Example

Stepper is configured through defineStepper(...steps). Use the code sample below to create StepperProvider, navigation, and controls in your app.

import { defineStepper } from "@hoag/ui/components/stepper";
 
const {
  StepperProvider,
  StepperNavigation,
  StepperStep,
  StepperTitle,
  StepperPanel,
  StepperControls,
  useStepper,
} = defineStepper(
  { id: "details", title: "Details" },
  { id: "review", title: "Review" },
  { id: "confirm", title: "Confirm" },
);
 
function StepperContent() {
  const { methods } = useStepper();
 
  return (
    <StepperPanel>
      <p className="text-sm">Current step: {methods.currentStepData?.title}</p>
      <StepperControls>
        <button onClick={methods.prev} disabled={methods.isFirst}>
          Back
        </button>
        <button onClick={methods.next} disabled={methods.isLast}>
          Next
        </button>
      </StepperControls>
    </StepperPanel>
  );
}
 
export function StepperBasicExample() {
  return (
    <StepperProvider>
      <StepperNavigation>
        {methods.all.map((step) => (
          <StepperStep key={step.id} of={step}>
            <StepperTitle>{step.title}</StepperTitle>
          </StepperStep>
        ))}
      </StepperNavigation>
      <StepperContent />
    </StepperProvider>
  );
}

Preview - Basic

Current step: Details

Preview - Disabled Steps

Current step: Account

Preview - Vertical

Current step: Collect

Composition Pattern

import { StepperContext } from "@hoag/ui/components/stepper";
 
export function StepperContextSection() {
  return (
    <section className="space-y-3">
      <h3 className="text-sm font-medium">Stepper section</h3>
      <StepperContext />
    </section>
  );
}

Accessibility Checklist

  • Verify semantic roles and ARIA attributes for interactive behavior.
  • Keep keyboard navigation and focus visibility consistent in all states.
  • Ensure color contrast meets accessibility requirements in light and dark themes.
  • Provide screen reader context for dynamic state or content changes.

Testing Checklist

  • Add render tests for default and key variant states.
  • Add interaction tests for callbacks and state transitions.
  • Add visual regression checks for responsive and theme variations.
  • Cover edge states such as loading, empty, disabled, and error.

Production Tips

  • Wrap component logic in feature-level abstractions for domain behavior.
  • Keep visual variants centralized to avoid style drift across screens.
  • Reuse a single import path strategy for simpler refactors.
  • Mirror documented states in Storybook and QA checklists.

Named Exports

  • StepperContext
  • defineStepper
  • useStepper

API Reference

For authoritative prop signatures and implementation details, inspect:

  • packages/ui/src/components/stepper.tsx

MIT 2026 © @hoag/ui