Skip to main content
Vuetify0 is now a release candidate!
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

createStep

Extends createSingle with bounded or circular navigation. Built for wizards, multi-step forms, and onboarding flows.

Usage

The createStep composable manages a list of steps and allows navigation between them with configurable circular (wrapping) or bounded (stopping at edges) behavior. You register each step (with an id and value) in the order they should be navigated, then use the navigation methods to move

ts
import { createStep } from '@vuetify/v0'

// Bounded navigation (default) - for wizards, forms
const wizard = createStep({ circular: false })

wizard.onboard([
  { id: 'step1', value: 'Account Info' },
  { id: 'step2', value: 'Payment' },
  { id: 'step3', value: 'Confirmation' },
])

wizard.first()    // Go to step1
wizard.next()     // Go to step2
wizard.next()     // Go to step3
wizard.next()     // Stays at step3 (bounded)

// Circular navigation - for carousels, theme switchers
const carousel = createStep({ circular: true })

carousel.onboard([
  { id: 'slide1', value: 'First' },
  { id: 'slide2', value: 'Second' },
  { id: 'slide3', value: 'Third' },
])

carousel.last()   // Go to slide3
carousel.next()   // Wraps to slide1
carousel.prev()   // Wraps to slide3

Context / DI

Use createStepContext to share a step navigation instance across a component tree:

ts
import { createStepContext } from '@vuetify/v0'

export const [useWizard, provideWizard, wizard] =
  createStepContext({ namespace: 'my:wizard', circular: false })

// In parent component
provideWizard()

// In child component
const step = useWizard()
step.next()

Architecture

createStep extends createSingle with directional navigation:

Step Navigation Hierarchy

Use controls to zoom and pan. Click outside or press Escape to close.

Step Navigation Hierarchy

Reactivity

Step navigation state is always reactive. Use selectedIndex to derive disabled states for navigation buttons.

Property/MethodReactiveNotes
selectedIdComputed — current step ID
selectedIndexComputed — current step position
selectedItemComputed — current step ticket
selectedValueComputed — current step value
step(count)Move by count positions — positive forward, negative backward[1]
Tip

Navigation button state Derive boundary checks from selectedIndex and registry size:

ts
const atFirst = toRef(() => selection.selectedIndex.value === 0)
const atLast  = toRef(() => selection.selectedIndex.value === selection.size - 1)

In circular mode, buttons are never disabled.

Examples

Multi-Step Checkout Wizard

A five-step checkout flow that puts the whole navigation contract in one composable and keeps the markup purely presentational. useCheckout registers the steps with onboard, calls first() to land on Cart, and then derives everything the UI needs from selectedIndex and selectedValuecurrent for the active panel, isFirst and isLast for the button guards, and a progress percentage for the connecting line. Because each derivation is a toRef, the view updates with no extra state to keep in sync.

The Gift wrap step is registered with disabled: true, so next() and prev() step right over it with no manual guard in the template; step(count) does the boundary math and skips disabled tickets automatically. The composable also projects the tickets into a rows view-model that tags each step as done, active, upcoming, or off, which is the only thing the wizard component reads to style its circles. Clicking a circle calls select(id) for non-linear jumps, and select is a no-op on a disabled ticket, so the skipped step stays unreachable from every entry point.

This is the composable-only shape: useCheckout owns the state and exposes a flat object of refs and methods, CheckoutWizard renders the v0 Button surface against that object, and the entry wires them together. Switch the instance to createStep({ circular: true }) and next()/prev() wrap at the ends instead of clamping — the carousel behavior. The Prev/Next buttons won’t wrap on their own, though: isFirst/isLast are derived from the index alone (0 and size - 1), so their :disabled guards stay true at the boundaries regardless of circular. To let the buttons wrap too, drop the isFirst/isLast guards in circular mode — gate them on a non-circular flag instead. For single selection without navigation methods, reach for createSingle; for the provided component version, see Step.

FileRole
useCheckout.tsOwns the createStep instance, registers steps, and derives index, current, progress, and the row view-model
CheckoutWizard.vueRenders the progress track, step circles, active panel, and navigation buttons from the composable
checkout-wizard.vueEntry point that instantiates the composable and shows the live step and progress readout

Cart

Review the items in your basket before you check out.

Step 1 of 5 · Gift wrap is unavailable and is skipped automatically · 0% complete

FAQ

Discord
Need help? Join our community for support and discussions ↗

API Reference

The following API details are for the createStep composable.

  1. step(-2) moves back two positions; step(3) skips ahead three. In circular mode it wraps at both ends; in bounded mode it clamps at the first and last steps. Disabled steps are skipped automatically. ↩︎

Was this page helpful?

Ctrl+/