Vize

use-stepper

Linear multi-step flow (wizards, onboarding, checkout) with typed step names.

Package @vizejs/composable/use-stepper
Own the source vize lib pull composable:use-stepper
Runtime exports useStepper
Gzip budget 1024 B

Minimal setup

Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).

vp install @vizejs/composable

Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.

import { useStepper } from "@vizejs/composable/use-stepper";

Try it

Review a registration in editable steps

Move through attendee, session, and review screens while retaining the values needed when an earlier step is edited.

Open the interactive example

What to observe: Edit the attendee, choose a session, and continue to Review. Next disables on the last step. Choose Attendee in the step list to revise the name, then return through Session; both values remain and the review reflects the edit.

index is zero-based and readonly; current is the typed step name. Navigation changes only the cursor. The name and session are independent writable Vue refs, so conditional screens retain their data. goBackTo only moves to an earlier step; the example disables later step buttons. Previous/Next controls expose the first/last boundaries and the step list marks its current item with aria-current. This example navigates and reviews local values without validation or submission. All state is synchronous and SSR-safe; no browser capability or cleanup is required.

Compare the initial and interacted states
Review a registration in editable steps: initial state
Initial state
Review a registration in editable steps: state after the verified interactions
After the verified interactions

Copy the example

Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.

<script setup lang="ts">
import { ref, useId } from "vue";
import { useStepper } from "@vizejs/composable/use-stepper";

const wizardId = useId();
const attendee = ref("Ada");
const session = ref("Compiler clinic");
const {
  stepNames,
  index,
  current,
  isFirst,
  isLast,
  isCurrent,
  isBefore,
  goToNext,
  goToPrevious,
  goBackTo,
} = useStepper(["attendee", "session", "review"]);
const titles = { attendee: "Attendee", session: "Session", review: "Review" } as const;
</script>

<template>
  <div class="composable-example">
    <p>Prepare a workshop registration in three steps. Edits stay available when you go back.</p>
    <ol aria-label="Registration steps">
      <li v-for="step in stepNames" :key="step">
        <button
          type="button"
          :disabled="!isBefore(step) && !isCurrent(step)"
          :aria-current="isCurrent(step) ? 'step' : undefined"
          @click="() => goBackTo(step)"
        >
          {{ titles[step] }}
        </button>
      </li>
    </ol>
    <output aria-live="polite"
      >Step {{ index + 1 }} of {{ stepNames.length }}: {{ titles[current] }}</output
    >
    <div v-if="current === 'attendee'">
      <label :for="`${wizardId}-attendee`">Workshop attendee</label>
      <input :id="`${wizardId}-attendee`" v-model="attendee" autocomplete="name" />
    </div>
    <div v-else-if="current === 'session'">
      <label :for="`${wizardId}-session`">Workshop session</label>
      <select :id="`${wizardId}-session`" v-model="session">
        <option>Compiler clinic</option>
        <option>Type checking clinic</option>
        <option>Editor tools clinic</option>
      </select>
    </div>
    <div v-else>
      <h3>Review registration</h3>
      <p>Attendee: {{ attendee || "Not entered" }}</p>
      <p>Session: {{ session }}</p>
      <p>This is a local review. No registration has been sent.</p>
    </div>
    <div class="example-actions">
      <button type="button" :disabled="isFirst" @click="goToPrevious">Previous step</button>
      <button type="button" :disabled="isLast" @click="goToNext">Next step</button>
    </div>
    <p>Use an earlier step button to edit it. Later steps open with Next step.</p>
  </div>
</template>

Runtime contract

Utility Category Stability SSR Hydration Cleanup Targets Host globals Uses
useStepper state experimental safe stable none web, server, worker, native, desktop, terminal — —

API

useStepper

Linear multi-step flow (wizards, onboarding, checkout) with typed step names. Pass a tuple of names (["account", "billing", "review"] as const, or a plain array literal thanks to const inference) or an object whose keys are the names and whose values carry per-step data; every navigation method only accepts declared names. Synchronous state: SSR-safe and nothing to dispose.

function useStepper<const Steps extends readonly string[]>( steps: Steps, initial?: NoInfer<Steps[number]>, ): Stepper<Steps[number], { readonly [Step in Steps[number]]: Step }>
const wizard = useStepper(["account", "billing", "review"]);
wizard.goTo("billing");
wizard.goTo("shipping"); // type error

useStepper

function useStepper<Steps extends Readonly<Record<string, unknown>>>( steps: Steps, initial?: NoInfer<keyof Steps & string>, ): Stepper<keyof Steps & string, Steps>

useStepper

function useStepper( steps: readonly string[] | Readonly<Record<string, unknown>>, initial?: string, ): Stepper<string, Readonly<Record<string, unknown>>>

Types

Stepper

Stepper state and navigation returned by useStepper.

Member Type Description
stepNames readonly Name[] Step names in order.
index Readonly<ShallowRef<number>> Zero-based index of the current step.
current ComputedRef<Name> Name of the current step.
currentValue ComputedRef<Values[Name]> Value of the current step (the name itself for array steps).
next ComputedRef<Name | undefined> Name of the next step, or undefined on the last.
previous ComputedRef<Name | undefined> Name of the previous step, or undefined on the first.
isFirst ComputedRef<boolean> Whether the current step is the first.
isLast ComputedRef<boolean> Whether the current step is the last.
at (index: number) => Name | undefined Step name at index, or undefined.
get <Step extends Name>(step: Step) => Values[Step] Value of a step.
goTo (step: Name) => void Jump to a step.
goToNext () => void Advance one step (no-op on the last).
goToPrevious () => void Go back one step (no-op on the first).
goBackTo (step: Name) => boolean Go back to an earlier step; later or current steps are ignored.
isCurrent (step: Name) => boolean Whether step is the current step.
isNext (step: Name) => boolean Whether step is the step right after the current one.
isPrevious (step: Name) => boolean Whether step is the step right before the current one.
isBefore (step: Name) => boolean Whether step comes before the current step.
isAfter (step: Name) => boolean Whether step comes after the current step.