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
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 slide3Context / DI
Use createStepContext to share a step navigation instance across a component tree:
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:
Reactivity
Step navigation state is always reactive. Use selectedIndex to derive disabled states for navigation buttons.
| Property/Method | Reactive | Notes |
|---|---|---|
selectedId | Computed — current step ID | |
selectedIndex | Computed — current step position | |
selectedItem | Computed — current step ticket | |
selectedValue | Computed — current step value | |
step(count) | Move by count positions — positive forward, negative backward |
step(count) 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.
Navigation button state Derive boundary checks from selectedIndex and registry size:
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 Stepper
Numbered steps with a progress bar, clickable navigation, and a disabled step that auto-skips.
Step 1 of 5 · Payment step is disabled (auto-skipped)
Functions
createStep
(_options?: StepOptions) => RCreates a new step instance with navigation through items. Extends `createSingle` with `first()`, `last()`, `next()`, `prev()`, and `step(count)` methods for sequential navigation. Supports both circular (wrapping) and bounded (stopping at edges) modes.
Options
disabled
MaybeRefOrGetter<boolean> | undefinedDisabled state for the entire model instance
Default: false
multiple
MaybeRefOrGetter<boolean> | undefinedAllow multiple tickets to be selected simultaneously
Default: false
mandatory
MaybeRefOrGetter<boolean | "force"> | undefinedControls mandatory selection behavior: - `false` (default): No mandatory selection enforcement - `true`: Prevents deselecting the last selected item - `'force'`: Automatically selects the first non-disabled item on registration
circular
boolean | undefinedEnable circular navigation (wrapping at boundaries). - true: Navigation wraps around (carousel behavior) - false: Navigation stops at boundaries (pagination behavior)
Default: false
Properties
selectedValues
ComputedRef<Set<E["value"] extends Ref<infer U, infer U> ? U : E["value"]>>Computed Set of selected ticket values
selectedId
ComputedRef<ID | undefined>selectedIndex
ComputedRef<number>selectedItem
ComputedRef<E | undefined>selectedValue
ComputedRef<E["value"] | undefined>Methods
move
(id: ID, toIndex: number) => E | undefinedSeek for a ticket based on direction and optional predicate
seek
(direction?: "first" | "last", from?: number, predicate?: (ticket) => boolean) => E | undefinedon
<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => voidListen for registry events
off
<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => voidStop listening for registry events
emit
<K extends Extensible<RegistryEventName>>(event: K, data: EventPayload<E, K>) => voidEmit an event with data
batch
<R>(fn: () => R) => RExecute operations in a batch, deferring cache invalidation and event emission until complete