Creative Tim UICreative Tim UI

Shadcn Stepper

PreviousNext

A step indicator component that displays progress through a multi-step process, perfect for wizards, forms, and onboarding flows.

1
2
3
"use client"

import * as React from "react"

import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
  Stepper,
  StepperHeader,
  StepperIcon,
  StepperItem,
  StepperSeparator,
} from "@/components/ui/stepper"

export function StepperDemo() {
  const [step, setStep] = React.useState(0)

  return (
    <div className="w-full">
      <Stepper
        value={step}
        onChange={setStep}
        className="relative flex items-center"
      >
        <StepperItem value={0} disabled={step < 0} className="flex-1">
          <StepperHeader className="flex w-full items-center">
            <StepperIcon
              className={cn(
                "relative z-10 flex size-10 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                step >= 0
                  ? "border-primary bg-primary text-primary-foreground"
                  : "border-muted bg-background text-muted-foreground"
              )}
            >
              1
            </StepperIcon>
            <StepperSeparator
              className={cn(
                "mx-2 h-0.5 flex-1 transition-colors",
                step > 0 ? "bg-primary" : "bg-muted"
              )}
            />
          </StepperHeader>
        </StepperItem>
        <StepperItem value={1} disabled={step < 1} className="flex-1">
          <StepperHeader className="flex w-full items-center">
            <StepperIcon
              className={cn(
                "relative z-10 flex size-10 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                step >= 1
                  ? "border-primary bg-primary text-primary-foreground"
                  : "border-muted bg-background text-muted-foreground"
              )}
            >
              2
            </StepperIcon>
            <StepperSeparator
              className={cn(
                "mx-2 h-0.5 flex-1 transition-colors",
                step > 1 ? "bg-primary" : "bg-muted"
              )}
            />
          </StepperHeader>
        </StepperItem>
        <StepperItem value={2} disabled={step < 2} className="flex-1">
          <StepperHeader className="flex w-full items-center">
            <StepperIcon
              className={cn(
                "relative z-10 flex size-10 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                step >= 2
                  ? "border-primary bg-primary text-primary-foreground"
                  : "border-muted bg-background text-muted-foreground"
              )}
            >
              3
            </StepperIcon>
          </StepperHeader>
        </StepperItem>
      </Stepper>

      <div className="mt-14 flex w-full justify-between gap-4">
        <Button disabled={step === 0} onClick={() => setStep(step - 1)}>
          Previous
        </Button>
        <Button disabled={step === 2} onClick={() => setStep(step + 1)}>
          Next
        </Button>
      </div>
    </div>
  )
}

Installation

pnpm dlx @creative-tim/ui@latest add stepper

Usage

import StepperDemo from "@/components/stepper-demo"
<StepperDemo />

Examples

Stepper with Icon

A stepper component that uses icons instead of numbers to represent each step, providing a more visual and intuitive way to navigate through the process.

"use client"

import * as React from "react"
import { Home, Settings, User } from "lucide-react"

import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
  Stepper,
  StepperHeader,
  StepperIcon,
  StepperItem,
  StepperSeparator,
} from "@/components/ui/stepper"

export function StepperWithIcon() {
  const [step, setStep] = React.useState(0)

  return (
    <div className="w-full">
      <Stepper
        value={step}
        onChange={setStep}
        className="relative flex items-center"
      >
        <StepperItem value={0} disabled={step < 0} className="flex-1">
          <StepperHeader className="flex w-full items-center">
            <StepperIcon
              className={cn(
                "relative z-10 flex size-10 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                step === 0
                  ? "border-primary bg-primary text-primary-foreground"
                  : step > 0
                    ? "border-primary bg-primary/10 text-primary"
                    : "border-neutral-300 bg-neutral-100 text-neutral-400"
              )}
            >
              <Home className="h-6 w-6" />
            </StepperIcon>
            <StepperSeparator
              className={cn(
                "mx-2 h-0.5 flex-1 transition-colors",
                step > 0 ? "bg-primary" : "bg-neutral-200"
              )}
            />
          </StepperHeader>
        </StepperItem>
        <StepperItem value={1} disabled={step < 1} className="flex-1">
          <StepperHeader className="flex w-full items-center">
            <StepperIcon
              className={cn(
                "relative z-10 flex size-10 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                step === 1
                  ? "border-primary bg-primary text-primary-foreground"
                  : step > 1
                    ? "border-primary bg-primary/10 text-primary"
                    : "border-neutral-300 bg-neutral-100 text-neutral-400"
              )}
            >
              <User className="h-6 w-6" />
            </StepperIcon>
            <StepperSeparator
              className={cn(
                "mx-2 h-0.5 flex-1 transition-colors",
                step > 1 ? "bg-primary" : "bg-neutral-200"
              )}
            />
          </StepperHeader>
        </StepperItem>
        <StepperItem value={2} disabled={step < 2} className="flex-1">
          <StepperHeader className="flex w-full items-center">
            <StepperIcon
              className={cn(
                "relative z-10 flex size-10 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                step === 2
                  ? "border-primary bg-primary text-primary-foreground"
                  : "border-neutral-300 bg-neutral-100 text-neutral-400"
              )}
            >
              <Settings className="h-6 w-6" />
            </StepperIcon>
          </StepperHeader>
        </StepperItem>
      </Stepper>

      <div className="mt-14 flex w-full justify-between gap-4">
        <Button disabled={step === 0} onClick={() => setStep(step - 1)}>
          Previous
        </Button>
        <Button disabled={step === 2} onClick={() => setStep(step + 1)}>
          Next
        </Button>
      </div>
    </div>
  )
}

Stepper with Dots

A minimalist stepper variant that uses small dots instead of numbered circles, creating a cleaner and more subtle progress indicator.

"use client"

import * as React from "react"

import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
  Stepper,
  StepperHeader,
  StepperIcon,
  StepperItem,
  StepperSeparator,
} from "@/components/ui/stepper"

export function StepperWithDots() {
  const [step, setStep] = React.useState(0)

  return (
    <div className="w-full">
      <Stepper
        value={step}
        onChange={setStep}
        className="relative flex items-center"
      >
        <StepperItem value={0} disabled={step < 0} className="flex-1">
          <StepperHeader className="flex w-full items-center">
            <StepperIcon
              className={cn(
                "relative z-10 flex size-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                step === 0
                  ? "border-primary bg-primary"
                  : step > 0
                    ? "border-primary bg-primary/20"
                    : "border-neutral-300 bg-neutral-200"
              )}
            />
            <StepperSeparator
              className={cn(
                "mx-2 h-0.5 flex-1 transition-colors",
                step > 0 ? "bg-primary" : "bg-neutral-200"
              )}
            />
          </StepperHeader>
        </StepperItem>
        <StepperItem value={1} disabled={step < 1} className="flex-1">
          <StepperHeader className="flex w-full items-center">
            <StepperIcon
              className={cn(
                "relative z-10 flex size-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                step === 1
                  ? "border-primary bg-primary"
                  : step > 1
                    ? "border-primary bg-primary/20"
                    : "border-neutral-300 bg-neutral-200"
              )}
            />
            <StepperSeparator
              className={cn(
                "mx-2 h-0.5 flex-1 transition-colors",
                step > 1 ? "bg-primary" : "bg-neutral-200"
              )}
            />
          </StepperHeader>
        </StepperItem>
        <StepperItem value={2} disabled={step < 2} className="flex-1">
          <StepperHeader className="flex w-full items-center">
            <StepperIcon
              className={cn(
                "relative z-10 flex size-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                step === 2
                  ? "border-primary bg-primary"
                  : "border-neutral-300 bg-neutral-200"
              )}
            />
          </StepperHeader>
        </StepperItem>
      </Stepper>

      <div className="mt-14 flex w-full justify-between gap-4">
        <Button disabled={step === 0} onClick={() => setStep(step - 1)}>
          Previous
        </Button>
        <Button disabled={step === 2} onClick={() => setStep(step + 1)}>
          Next
        </Button>
      </div>
    </div>
  )
}

Stepper with Content

A stepper component that includes descriptive content below each step, providing additional context and information about what each step entails.

Step 1

Details about your account.

Step 2

Details about your account.

Step 3

Details about your account.

"use client"

import * as React from "react"
import { Home, Settings, User } from "lucide-react"

import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
  Stepper,
  StepperBody,
  StepperHeader,
  StepperIcon,
  StepperItem,
  StepperSeparator,
} from "@/components/ui/stepper"

export function StepperWithContent() {
  const [step, setStep] = React.useState(0)

  return (
    <div className="w-full">
      <Stepper value={step} onChange={setStep} className="relative">
        <div className="flex w-full items-start">
          <StepperItem value={0} disabled={step < 0} className="flex-1">
            <div className="flex flex-col items-center">
              <div className="relative w-full">
                <StepperSeparator
                  className={cn(
                    "absolute top-0 left-1/2 h-0.5 w-full -translate-x-1/2 transition-colors",
                    step > 0 ? "bg-primary" : "bg-muted"
                  )}
                />
              </div>
              <StepperHeader className="mt-2 flex w-full items-center">
                <StepperIcon
                  className={cn(
                    "relative z-10 mx-auto flex size-10 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                    step >= 0
                      ? "border-primary bg-primary text-primary-foreground"
                      : "border-muted bg-background text-muted-foreground"
                  )}
                >
                  <Home className="h-6 w-6" />
                </StepperIcon>
              </StepperHeader>
              <StepperBody className="mt-4 text-center">
                <h6
                  className={cn(
                    "text-base font-semibold",
                    step >= 0 ? "text-primary" : "text-foreground"
                  )}
                >
                  Step 1
                </h6>
                <p className="text-muted-foreground mt-1 text-sm">
                  Details about your account.
                </p>
              </StepperBody>
            </div>
          </StepperItem>
          <StepperItem value={1} disabled={step < 1} className="flex-1">
            <div className="flex flex-col items-center">
              <div className="relative w-full">
                <StepperSeparator
                  className={cn(
                    "absolute top-0 left-1/2 h-0.5 w-full -translate-x-1/2 transition-colors",
                    step > 1 ? "bg-primary" : "bg-muted"
                  )}
                />
              </div>
              <StepperHeader className="mt-2 flex w-full items-center">
                <StepperIcon
                  className={cn(
                    "relative z-10 mx-auto flex size-10 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                    step >= 1
                      ? "border-primary bg-primary text-primary-foreground"
                      : "border-muted bg-background text-muted-foreground"
                  )}
                >
                  <User className="h-6 w-6" />
                </StepperIcon>
              </StepperHeader>
              <StepperBody className="mt-4 text-center">
                <h6
                  className={cn(
                    "text-base font-semibold",
                    step >= 1 ? "text-primary" : "text-foreground"
                  )}
                >
                  Step 2
                </h6>
                <p className="text-muted-foreground mt-1 text-sm">
                  Details about your account.
                </p>
              </StepperBody>
            </div>
          </StepperItem>
          <StepperItem value={2} disabled={step < 2} className="flex-1">
            <div className="flex flex-col items-center">
              <StepperHeader className="mt-2 flex w-full items-center">
                <StepperIcon
                  className={cn(
                    "relative z-10 mx-auto flex size-10 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                    step >= 2
                      ? "border-primary bg-primary text-primary-foreground"
                      : "border-muted bg-background text-muted-foreground"
                  )}
                >
                  <Settings className="h-6 w-6" />
                </StepperIcon>
              </StepperHeader>
              <StepperBody className="mt-4 text-center">
                <h6
                  className={cn(
                    "text-base font-semibold",
                    step >= 2 ? "text-primary" : "text-foreground"
                  )}
                >
                  Step 3
                </h6>
                <p className="text-muted-foreground mt-1 text-sm">
                  Details about your account.
                </p>
              </StepperBody>
            </div>
          </StepperItem>
        </div>
      </Stepper>

      <div className="mt-14 flex w-full justify-between gap-4">
        <Button disabled={step === 0} onClick={() => setStep(step - 1)}>
          Previous
        </Button>
        <Button disabled={step === 2} onClick={() => setStep(step + 1)}>
          Next
        </Button>
      </div>
    </div>
  )
}

Stepper Custom Styles

A stepper component with custom styling applied, demonstrating how to customize the appearance to match your design system with a primary-colored background and white indicators.

"use client"

import * as React from "react"

import { cn } from "@/lib/utils"
import { Card } from "@/components/ui/card"
import {
  Stepper,
  StepperHeader,
  StepperIcon,
  StepperItem,
  StepperSeparator,
} from "@/components/ui/stepper"

export function StepperCustomStyles() {
  const [step, setStep] = React.useState(0)

  return (
    <Card className="bg-primary mx-auto w-full rounded-full p-6">
      <Stepper value={step} onChange={setStep} className="relative">
        <StepperItem value={0} className="flex-1">
          <StepperHeader className="flex w-full flex-col items-center">
            <div className="flex w-full items-center">
              <StepperIcon
                className={cn(
                  "relative z-10 flex size-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                  step >= 0
                    ? "border-white bg-white"
                    : "border-gray-300 bg-gray-300"
                )}
              />
              {step < 3 && (
                <StepperSeparator
                  className={cn(
                    "mx-2 h-0.5 flex-1 transition-colors",
                    step > 0 ? "bg-white" : "bg-gray-300"
                  )}
                />
              )}
            </div>
          </StepperHeader>
        </StepperItem>
        <StepperItem value={1} className="flex-1">
          <StepperHeader className="flex w-full flex-col items-center">
            <div className="flex w-full items-center">
              <StepperIcon
                className={cn(
                  "relative z-10 flex size-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                  step >= 1
                    ? "border-white bg-white"
                    : "border-gray-300 bg-gray-300"
                )}
              />
              {step < 3 && (
                <StepperSeparator
                  className={cn(
                    "mx-2 h-0.5 flex-1 transition-colors",
                    step > 1 ? "bg-white" : "bg-gray-300"
                  )}
                />
              )}
            </div>
          </StepperHeader>
        </StepperItem>
        <StepperItem value={2} className="flex-1">
          <StepperHeader className="flex w-full flex-col items-center">
            <div className="flex w-full items-center">
              <StepperIcon
                className={cn(
                  "relative z-10 flex size-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                  step >= 2
                    ? "border-white bg-white"
                    : "border-gray-300 bg-gray-300"
                )}
              />
              {step < 3 && (
                <StepperSeparator
                  className={cn(
                    "mx-2 h-0.5 flex-1 transition-colors",
                    step > 2 ? "bg-white" : "bg-gray-300"
                  )}
                />
              )}
            </div>
          </StepperHeader>
        </StepperItem>
        <StepperItem value={3} className="flex-1">
          <StepperHeader className="flex w-full flex-col items-center">
            <StepperIcon
              className={cn(
                "relative z-10 flex size-4 shrink-0 items-center justify-center rounded-full border-2 transition-colors",
                step >= 3
                  ? "border-white bg-white"
                  : "border-gray-300 bg-gray-300"
              )}
            />
          </StepperHeader>
        </StepperItem>
      </Stepper>
    </Card>
  )
}

Best Practices

  • Use steppers for processes with 3-7 steps for optimal usability
  • Provide clear labels and descriptions for each step
  • Allow users to navigate backward through completed steps
  • Disable future steps to prevent skipping ahead
  • Show progress clearly with visual indicators
  • Consider using icons for better visual recognition
  • Provide navigation buttons (Previous/Next) for better control
  • Ensure the stepper is accessible with proper ARIA labels

Stepper components provide a clear way to guide users through multi-step processes. They're ideal for forms, wizards, onboarding flows, checkout processes, and any interface where users need to complete tasks in a specific sequence.