stepperform
StepPerform
A lightweight, reusable Vue 3 stepper wizard for multi-step forms.
StepPerform handles the step navigation, progress state, and wizard UI while your application remains responsible for form fields and validation.
- Vue 3
- JavaScript
- Pure CSS
- No Bootstrap dependency
- No VeeValidate dependency
- No Yup/Zod dependency
- Supports custom synchronous and asynchronous validation
- Per-step validation
- VeeValidate-compatible
- Responsive
- Lightweight
Installation
Install StepPerform from npm:
npm install stepperform
Basic Usage
Import the components:
<script setup>
import {
StepperWizard,
Step,
} from 'stepperform'
import 'stepperform/style.css'
</script>
Then create your wizard:
<template>
<StepperWizard
:header-title="[
'Personal Information',
'Contact Information',
'Summary',
]"
@finish="handleFinish"
>
<Step title="Personal Information">
<h3>Personal Information</h3>
<input
type="text"
placeholder="First name"
/>
</Step>
<Step title="Contact Information">
<h3>Contact Information</h3>
<input
type="email"
placeholder="Email"
/>
</Step>
<Step title="Summary">
<h3>Summary</h3>
<p>Your information is ready to submit.</p>
</Step>
</StepperWizard>
</template>
<script setup>
function handleFinish() {
console.log('Form completed')
}
</script>
Per-Step Validation
StepPerform does not provide its own validation library.
Instead, each <Step> can receive a validate function.
<Step
title="Personal Information"
:validate="validatePersonal"
>
<!-- fields -->
</Step>
The validator is executed when the user clicks Next.
If the validator returns false, the wizard stays on the current step.
If it returns true, the wizard proceeds to the next step.
Simple Example
<script setup>
import { ref } from 'vue'
const firstName = ref('')
function validatePersonal() {
return firstName.value.trim() !== ''
}
</script>
<template>
<StepperWizard>
<Step
title="Personal Information"
:validate="validatePersonal"
>
<input
v-model="firstName"
type="text"
placeholder="First name"
/>
</Step>
<Step title="Summary">
<p>Ready to submit.</p>
</Step>
</StepperWizard>
</template>
Validation Return Values
A step validator can return:
Boolean
function validateStep() {
return true
}
or:
function validateStep() {
return false
}
Validation Object
Validators can also return an object containing valid:
async function validateStep() {
return {
valid: true,
}
}
or:
async function validateStep() {
return {
valid: false,
}
}
StepPerform uses the valid property to determine whether the user can continue.
Multiple Fields Per Step
You can validate multiple fields with a single validator.
<script setup>
function validatePersonal() {
const firstNameValid =
firstName.value.trim() !== ''
const lastNameValid =
lastName.value.trim() !== ''
return firstNameValid && lastNameValid
}
</script>
Then:
<Step
title="Personal Information"
:validate="validatePersonal"
>
<!-- multiple fields -->
</Step>
This allows your application to keep complete control over how fields are validated.
Async Validation
Validators can be asynchronous.
<script setup>
async function validateEmail() {
const available = await checkEmailAvailability()
return available
}
</script>
Use it normally:
<Step
title="Email"
:validate="validateEmail"
>
<!-- email field -->
</Step>
StepPerform waits for the Promise before deciding whether to continue.
VeeValidate
StepPerform does not depend on VeeValidate, but it works well with it.
Install VeeValidate separately in your application:
npm install vee-validate
Then use VeeValidate's validation functions as the Step validator.
<script setup>
import {
Form,
Field,
ErrorMessage,
} from 'vee-validate'
</script>
<template>
<Form
v-slot="{ validateField }"
>
<StepperWizard
:header-title="[
'First Name',
'Middle Name',
'Last Name',
]"
@finish="handleFinish"
>
<Step
title="First Name"
:validate="
() => validateField('first_name')
"
>
<Field
name="first_name"
class="form-control"
/>
<ErrorMessage
name="first_name"
/>
</Step>
<Step
title="Middle Name"
:validate="
() => validateField('middle_name')
"
>
<Field
name="middle_name"
class="form-control"
/>
<ErrorMessage
name="middle_name"
/>
</Step>
<Step
title="Last Name"
:validate="
() => validateField('last_name')
"
>
<Field
name="last_name"
class="form-control"
/>
<ErrorMessage
name="last_name"
/>
</Step>
</StepperWizard>
</Form>
</template>
The important part is:
:validate="
() => validateField('first_name')
"
StepPerform calls the function when the user attempts to continue.
VeeValidate remains completely optional.
Global Validation
You can also provide a validator directly to <StepperWizard>.
<StepperWizard
:validate="validateStep"
>
...
</StepperWizard>
Example:
async function validateStep() {
return true
}
However, per-step validation is recommended because it keeps each step's validation logic close to that step.
StepperWizard Props
header-title
Array of labels displayed in the stepper header.
<StepperWizard
:header-title="[
'Personal',
'Contact',
'Summary',
]"
>
Default:
[]
show-header
Controls whether the stepper header is displayed.
<StepperWizard
:show-header="false"
>
Default:
true
validate
Optional global validation function.
<StepperWizard
:validate="validateStep"
>
Per-step validate functions take priority.
Step Props
title
The title associated with the step.
<Step title="Personal Information">
...
</Step>
validate
Optional validation function.
<Step
title="Personal Information"
:validate="validatePersonal"
>
...
</Step>
The function can return:
true
false
or:
{
valid: true
}
It can also return a Promise.
Navigation Components
StepPerform provides three navigation components.
StepNext
<StepNext
:action="next"
/>
StepPrevious
<StepPrevious
:action="previous"
/>
StepConfirm
<StepConfirm
:action="confirm"
/>
In normal usage, StepperWizard handles these automatically.
Events
finish
Emitted when the user reaches the final step and confirms.
<StepperWizard
@finish="handleFinish"
>
Example:
function handleFinish() {
console.log('Wizard completed')
}
change
Emitted when the current step changes.
<StepperWizard
@change="handleStepChange"
>
Example:
function handleStepChange(step) {
console.log('Current step:', step)
}
Programmatic Step Control
StepPerform exposes the useStepperForm composable for applications that need direct control over the step state.
import {
useStepperForm,
} from 'stepperform'
Example:
const {
step,
total,
isFirstStep,
isLastStep,
progress,
next,
previous,
goTo,
reset,
} = useStepperForm(3)
Available methods
next()
Move to the next step.
previous()
Move to the previous step.
goTo(2)
Move directly to step 2.
reset()
Return to the initial step.
State
step
Current step.
total
Total number of steps.
isFirstStep
Whether the current step is the first step.
isLastStep
Whether the current step is the last step.
progress
Current progress percentage.
Components
StepPerform exports:
import {
StepperWizard,
StepperHeader,
Step,
StepPrevious,
StepNext,
StepConfirm,
useStepperForm,
} from 'stepperform'
Global Registration
You can register StepPerform globally.
import {
createApp,
} from 'vue'
import App from './App.vue'
import StepPerform from 'stepperform'
import 'stepperform/style.css'
const app = createApp(App)
app.use(StepPerform)
app.mount('#app')
After registration, you can use:
<StepperWizard>
<Step title="First">
...
</Step>
<Step title="Second">
...
</Step>
</StepperWizard>
Styling
StepPerform includes its own CSS.
Import it once:
import 'stepperform/style.css'
StepPerform does not require:
- Bootstrap
- Bootstrap Icons
- Tailwind CSS
- Vuetify
- another UI framework
Your application can use any CSS framework or design system alongside StepPerform, but none is required.
The package's built-in styles handle the stepper, navigation buttons, progress indicators, and responsive behavior.
Forms and Validation
StepPerform intentionally separates the wizard from form validation.
StepPerform handles
- Step registration
- Current step
- Next/previous navigation
- Progress
- Step validation callbacks
- Completion
- Stepper header
- Responsive stepper UI
Your application handles
- Form fields
- Form state
- Validation schemas
- Error messages
- API requests
- Submission
- Form libraries
This means you can use StepPerform with:
- VeeValidate
- Yup
- Zod
- custom validation
- native HTML validation
- other form libraries
without StepPerform needing to depend on them.
Example Project Structure
A consuming application could look like:
src/
├── components/
│ ├── Step1.vue
│ ├── Step2.vue
│ └── Step3.vue
│
├── composables/
│ └── validation.js
│
└── views/
└── WizardForm.vue
Example:
<StepperWizard
:header-title="[
'Personal',
'Contact',
'Summary',
]"
@finish="submitForm"
>
<Step
title="Personal"
:validate="validatePersonal"
>
<Step1 />
</Step>
<Step
title="Contact"
:validate="validateContact"
>
<Step2 />
</Step>
<Step title="Summary">
<Step3 />
</Step>
</StepperWizard>
Development
Clone the repository:
git clone https://github.com/amalyamsa/vue3-stepper-wizard.git
Install dependencies:
npm install
Build the package:
npm run build
Preview the build:
npm run preview
Testing the npm Package Locally
Build the package:
npm run build
Create a package archive:
npm pack
This creates a file similar to:
stepperform-1.0.0.tgz
Install that package into another Vue 3 application:
npm install /path/to/stepperform-1.0.0.tgz
Then test the package exactly as an npm consumer would.
Package Contents
The published package contains the compiled distribution:
stepperform/
├── dist/
│ ├── stepperform.css
│ ├── stepperform.js
│ └── stepperform.umd.cjs
├── LICENSE
├── README.md
└── package.json
Source files and development dependencies are not included in the published package.
Vue Compatibility
StepPerform is designed for:
Vue 3
Vue is declared as a peer dependency so the consuming application provides its own Vue installation.
License
MIT License.
Copyright (c) 2026 malaly
This version now clearly states that **Bootstrap is not required**, documents **per-step validation as the recommended approach**, and explains the separation between StepPerform and validation libraries.
Related Packages
Form Wizard Vue 3 is a simple stepper/wizard component. It can be easily customi...
Vue bindings for SmartWizard - modern, framework-agnostic wizard/stepper compone...
Core logic for SmartWizard - modern, framework-agnostic wizard/stepper component
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 1.1.0 | ^3.3.0 | MIT | |
| 1.0.0 | ^3.3.0 | MIT |