@doderasoftware/vue-stepper
| Install | |
|---|---|
npm install @doderasoftware/vue-stepper |
|
| Latest Version: | 1.0.9 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | Nov 28, 2025 |
| Links: | GitHub · npm |
@doderasoftware/vue-stepper
A headless, accessible, and fully customizable multi-step stepper component for Vue 3. Build complex forms, wizards, and onboarding flows with ease.
📖 Documentation | 📦 npm | 🐛 Issues
✨ Features
- 🎨 Fully Customizable - Complete UI control via
:uiprop system - 🌙 Dark Mode - Built-in dark mode support (follows system preference)
- 📱 Responsive - Sidebar collapses on mobile with dropdown menu
- 🔒 Step Locking - Prevent navigation to specific steps
- ⏭️ Optional Steps - Mark steps as optional with visual indicators
- 📊 Progress Tracking - Automatic step counters and progress bars
- 🎯 TypeScript - Full type safety out of the box
- 🪶 Zero Dependencies - No external CSS frameworks required
- 🎛️ Headless Ready - Use your own styles or the built-in ones
📦 Installation
npm install @doderasoftware/vue-stepper
That's it! Styles are automatically included - no additional CSS imports needed.
🚀 Quick Start
<template>
<Stepper
v-model="currentStep"
:steps="steps"
:can-go-next="canProceed"
sidebar-title="Registration"
@complete="handleComplete"
>
<template #default="{ currentStep: stepIndex }">
<PersonalInfo v-if="stepIndex === 0" v-model="formData.personal" />
<AccountDetails v-else-if="stepIndex === 1" v-model="formData.account" />
<Review v-else-if="stepIndex === 2" :data="formData" />
</template>
</Stepper>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { Stepper } from '@doderasoftware/vue-stepper'
const currentStep = ref(0)
const formData = ref({ personal: {}, account: {} })
const steps = [
{ category: 'Step 1', title: 'Personal Info', description: 'Enter your personal details' },
{ category: 'Step 2', title: 'Account Details', optional: true },
{ category: 'Step 3', title: 'Review & Submit' },
]
const canProceed = computed(() => {
if (currentStep.value === 0) {
return !!formData.value.personal.email
}
return true
})
function handleComplete() {
console.log('Form submitted:', formData.value)
}
</script>
🌙 Dark Mode
The component includes full dark mode support out of the box. It uses class-based dark mode - add the dark class to your <html> or <body> element to enable dark styles.
<!-- Enable dark mode via class on html/body -->
<html class="dark">
...
</html>
This approach is compatible with most dark mode implementations (Tailwind, manual toggle, etc.).
🎨 UI Customization
The :ui prop allows complete control over every element's styling. Pass class names to override the defaults:
<template>
<Stepper
v-model="currentStep"
:steps="steps"
:ui="{
root: 'my-stepper',
sidebar: 'bg-indigo-50 border-indigo-200',
navItemCurrent: 'bg-indigo-600 text-white',
indicatorCompleted: 'bg-indigo-600',
buttonPrimary: 'bg-gradient-to-r from-indigo-500 to-purple-600 hover:from-indigo-600 hover:to-purple-700',
progressFill: 'bg-indigo-600',
}"
>
<!-- your content -->
</Stepper>
</template>
Available UI Keys
| Key | Description |
|---|---|
root |
Root container |
sidebar |
Desktop sidebar container |
sidebarContent |
Sidebar inner content |
sidebarTitle |
Sidebar title text |
nav |
Navigation container |
navItem |
Step button - base |
navItemCurrent |
Step button - current |
navItemCompleted |
Step button - completed |
navItemDisabled |
Step button - disabled |
indicator |
Step indicator - base |
indicatorCurrent |
Step indicator - current |
indicatorCompleted |
Step indicator - completed |
indicatorDisabled |
Step indicator - disabled |
stepCategory |
Step category text |
stepTitle |
Step title text |
progressBar |
Progress bar track |
progressFill |
Progress bar fill |
main |
Main content area |
card |
Content card |
navigation |
Navigation buttons container |
button |
Button base |
buttonPrimary |
Primary button (next/complete) |
buttonSecondary |
Secondary button (back) |
buttonDisabled |
Disabled button state |
📋 Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue |
number |
0 |
Current step index (v-model) |
steps |
StepConfig[] |
required | Array of step configurations |
ui |
StepperUI |
{} |
UI customization object |
sidebarTitle |
string |
'Steps' |
Title displayed above the sidebar |
canGoNext |
boolean |
true |
Whether user can proceed to next step |
nextButtonText |
string |
'Continue' |
Text for the next button |
backButtonText |
string |
'Back' |
Text for the back button |
completeButtonText |
string |
'Complete' |
Text for the final step button |
showNavigation |
boolean |
true |
Show/hide navigation buttons |
showProgress |
boolean |
true |
Show/hide progress indicator |
showMobileHeader |
boolean |
true |
Show/hide mobile header |
showSidebar |
boolean |
true |
Show/hide desktop sidebar |
linear |
boolean |
true |
Restrict navigation to sequential steps only |
📡 Events
| Event | Payload | Description |
|---|---|---|
update:modelValue |
number |
Emitted when step index changes |
step-change |
{ from: number, to: number } |
Emitted on step navigation |
next |
StepChangeEvent |
Emitted when next button is clicked |
back |
StepChangeEvent |
Emitted when back button is clicked |
complete |
void |
Emitted when completing the last step |
🎰 Slots
| Slot | Props | Description |
|---|---|---|
default |
{ currentStep, currentStepConfig, goNext, goBack, ... } |
Main content area |
header |
- | Content above the step container |
title |
- | Title area inside step container |
sidebar-header |
- | Custom sidebar header |
sidebar-footer |
- | Custom sidebar footer |
step-indicator |
{ step, index, isCurrent, isCompleted, isDisabled } |
Custom step indicator |
back-icon |
- | Custom back button icon |
next-icon |
- | Custom next button icon |
📐 Step Configuration
interface StepConfig {
id?: string | number
category: string
title: string
disabled?: boolean
optional?: boolean
}
🪝 Composable
Use the useMultiStep composable for headless control:
import { useMultiStep } from '@doderasoftware/vue-stepper'
const {
currentStep,
isFirstStep,
isLastStep,
progress,
goNext,
goBack,
goToStep,
isStepCompleted,
reset,
} = useMultiStep({
steps: mySteps,
initialStep: 0,
linear: true,
onStepChange: ({ from, to }) => console.log(`Step changed from ${from} to ${to}`),
})
🔗 Links
📄 License
MIT © Dodera Software SRL
Related Packages
Vue bindings for SmartWizard - modern, framework-agnostic wizard/stepper compone...
Core logic for SmartWizard - modern, framework-agnostic wizard/stepper component
URL hash + browser history navigation extension for SmartWizard
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 1.0.9 | ^3.3.0 | MIT | |
| 1.0.8 | ^3.3.0 | MIT | |
| 1.0.7 | ^3.3.0 | MIT | |
| 1.0.6 | ^3.3.0 | MIT | |
| 1.0.5 | ^3.3.0 | MIT | |
| 1.0.4 | ^3.3.0 | MIT | |
| 1.0.3 | ^3.3.0 | MIT | |
| 1.0.2 | ^3.3.0 | MIT | |
| 1.0.1 | ^3.3.0 | MIT | |
| 1.0.0 | ^3.3.0 | MIT |