Components

Stepper

Guide users through a sequence of steps with UiStepper.

UiStepper renders a horizontal or vertical progress indicator for multi-step flows (checkout, onboarding, wizards). Each step derives its status — upcoming, current, or completed — from where activeStep sits within the steps array. The component is uncontrolled by default: keep activeStep and the updateActiveStep emit in sync to drive it from a parent (v-model style).

Basic usage

<script setup lang="ts">
import { ref } from 'vue'

const activeStep = ref('profile')
const steps = [
  { id: 'account', label: 'Account', description: 'Create your credentials' },
  { id: 'profile', label: 'Profile', description: 'Tell us about yourself' },
  { id: 'billing', label: 'Billing', description: 'Add a payment method' },
  { id: 'confirm', label: 'Confirm', description: 'Review and finish' },
]
</script>

<template>
  <UiStepper
    :steps="steps"
    :active-step="activeStep"
    @update-active-step="activeStep = $event"
  />
</template>

Steps before activeStep render as completed with a check mark; the active step gets aria-current="step"; the rest render as upcoming.

Vertical layout

Set vertical to stack steps in a column, useful for sidebars or narrow layouts.

<template>
  <UiStepper :steps="steps" :active-step="activeStep" vertical />
</template>

Linear progression

Set linear to block selecting any step ahead of the current one — users can still navigate back to a completed step, but can't skip forward.

<template>
  <UiStepper :steps="steps" :active-step="activeStep" linear @update-active-step="activeStep = $event" />
</template>

Step icons

Give a step an icon (Material Symbols code point) to render it instead of the step number. Completed steps always show a check mark regardless of icon.

<script setup lang="ts">
const steps = [
  { id: 'cart', label: 'Cart', icon: '&#xe8cc;' },
  { id: 'shipping', label: 'Shipping', icon: '&#xe8ca;' },
  { id: 'payment', label: 'Payment', icon: '&#xe870;' },
  { id: 'done', label: 'Done', icon: '&#xe5ca;' },
]
</script>

<template>
  <UiStepper :steps="steps" active-step="shipping" />
</template>

Disabled step

Mark a step disabled to remove it from keyboard navigation and block selection entirely, regardless of linear.

<template>
  <UiStepper
    :steps="[
      { id: 'account', label: 'Account' },
      { id: 'profile', label: 'Profile' },
      { id: 'billing', label: 'Billing', disabled: true },
      { id: 'confirm', label: 'Confirm' },
    ]"
    active-step="profile"
  />
</template>

Props

PropTypeDefaultDescription
stepsIStepItem[]Step items: { id, label, description?, icon?, disabled? }.
activeStepstringfirst stepThe id of the step that should be active.
verticalbooleanfalseRenders the stepper as a vertical list.
linearbooleanfalseBlocks selecting a step ahead of the current one.
customClassstring | string[] | Record<string, boolean> | nullExtra classes for the stepper root element.

Emits: updateActiveStep with the selected step's id.

Keyboard support mirrors UiTabs: arrow keys move roving focus between selectable steps (skipping disabled ones, and — in linear mode — steps ahead of the current one), Home/End jump to the first/last selectable step.
Copyright © 2026