Skip to content

Wizard Component

A clickable stepper component for visualizing and navigating multi-step workflows such as forms, setup wizards, and checkout flows. Renders step circles with connecting progress bars, optional labels, and active/completed/inactive visual states.


Table of Contents


Import

ts
import { Wizard } from "dolphin-components";
import type { WizardProps } from "dolphin-components";

Basic Usage

vue
<template>
  <Wizard
    :totalSteps="4"
    :currentStep="step"
    @step-change="step = $event"
  />

  <div class="mt-4 flex gap-2">
    <button @click="step--" :disabled="step <= 1" class="btn btn-outline-secondary">Previous</button>
    <button @click="step++" :disabled="step >= 4" class="btn btn-primary">Next</button>
  </div>
</template>

<script setup>
import { ref } from "vue";
import { Wizard } from "dolphin-components";

const step = ref(1);
</script>

Props

PropTypeDefaultDescription
totalStepsnumber4Total number of steps to render.
currentStepnumber1The currently active step (1-based index).
classNamestring""Custom CSS classes for the stepper container.
stepLabelsstring[] | nullnullOptional labels displayed below each step circle.
onStepChange((step: number) => void) | nullnullOptional callback invoked when a step circle is clicked.

Events

EventPayloadDescription
step-changenumberEmitted when a step circle is clicked. Passes the step number.

Slots

This component does not provide any slots.


TypeScript Interfaces

typescript
interface WizardProps {
  totalSteps?: number;
  currentStep?: number;
  className?: string;
  stepLabels?: string[] | null;
  onStepChange?: ((step: number) => void) | null;
}

Usage Examples

With Step Labels

vue
<template>
  <div class="max-w-[900px] mx-auto mt-8">
    <Wizard
      :totalSteps="5"
      :currentStep="currentStep"
      :stepLabels="['Setup', 'Config', 'Review', 'Deploy', 'Done']"
      @step-change="handleStepChange"
    />

    <div class="mt-4 flex gap-2">
      <button @click="currentStep--" :disabled="currentStep <= 1" class="btn btn-outline-secondary">
        Previous
      </button>
      <button @click="currentStep++" :disabled="currentStep >= 5" class="btn btn-primary">
        Next
      </button>
    </div>

    <p class="mt-2 text-sm text-gray-600">
      Step {{ currentStep }}: {{ ['Setup', 'Config', 'Review', 'Deploy', 'Done'][currentStep - 1] }}
    </p>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";
import { Wizard } from "dolphin-components";

const currentStep = ref(1);

const handleStepChange = (step: number) => {
  currentStep.value = step;
};
</script>

Without Labels (Numbered Steps Only)

vue
<Wizard :totalSteps="3" :currentStep="step" @step-change="step = $event" />

With Custom Container Styling

vue
<Wizard
  :totalSteps="4"
  :currentStep="2"
  className="bg-gray-50 p-6 rounded-lg"
  :stepLabels="['Info', 'Address', 'Payment', 'Confirm']"
/>

Integration with Form Sections

vue
<template>
  <Wizard
    :totalSteps="3"
    :currentStep="step"
    :stepLabels="['Personal', 'Address', 'Review']"
    @step-change="step = $event"
  />

  <div v-if="step === 1" class="mt-6">
    <h3>Personal Information</h3>
    <input class="input-text" v-model="form.name" placeholder="Full Name" />
    <input class="input-text mt-3" v-model="form.email" placeholder="Email" />
  </div>

  <div v-if="step === 2" class="mt-6">
    <h3>Address</h3>
    <input class="input-text" v-model="form.address" placeholder="Street Address" />
    <input class="input-text mt-3" v-model="form.city" placeholder="City" />
  </div>

  <div v-if="step === 3" class="mt-6">
    <h3>Review</h3>
    <p>Name: {{ form.name }}</p>
    <p>Email: {{ form.email }}</p>
    <p>Address: {{ form.address }}, {{ form.city }}</p>
  </div>
</template>

<script setup>
import { ref, reactive } from "vue";
import { Wizard } from "dolphin-components";

const step = ref(1);
const form = reactive({ name: "", email: "", address: "", city: "" });
</script>

Screenshots

  • With Labels:

wizard stepper image

  • Without Labels:

wizard stepper image


Visual States

Each step circle has one of three visual states:

StateAppearance
CompletedFilled background with a checkmark or step number
CurrentActive highlight with ring/shadow effect
InactiveGray/muted appearance for future steps

The connecting progress bars fill proportionally based on the current step's position.


Best Practices

  1. Use step labels for clarity — Labels help users understand each step's purpose at a glance.
  2. Keep steps to 3–7 — Too many steps may overwhelm users. Consider grouping related steps.
  3. Allow backward navigation — Let users click completed steps to go back and edit.
  4. Show step content conditionally — Use v-if with the step number to show the appropriate form section.

Troubleshooting

Steps not clickable

  • Ensure the @step-change event is handled to update the currentStep value.
  • Without an event handler, clicking steps has no visible effect.

Labels misaligned

  • Ensure the stepLabels array length matches totalSteps.
  • If fewer labels are provided, extra steps will have no label.