Prompt
How do I create a multi step form in Vue.js?
Latest observation
Aug 27, 2026
OpenAI APIWeb search: off
A common way to build a multi-step form in Vue is to:
- Keep track of the current step in component state
- Show only the fields for that step
- Validate the current step before moving on
- Collect all form data in one object
- Submit when the final step is complete
Below is a simple Vue 3 example using the Composition API.
Example: Multi-step form
MultiStepForm.vue
<template>
<form @submit.prevent="handleSubmit">
<!-- Step indicator -->
<div class="steps">
<span :class="{ active: currentStep === 1 }">1. Account</span>
<span :class="{ active: currentStep === 2 }">2. Profile</span>
<span :class="{ active: currentStep === 3 }">3. Review</span>
</div>
<!-- Step 1 -->
<div v-if="currentStep === 1">
<h2>Account Info</h2>
<label>
Email:
<input v-model="form.email" type="email" />
</label>
<label>
Password:
<input v-model="form.password" type="password" />
</label>
</div>
<!-- Step 2 -->
<div v-if="currentStep === 2">
<h2>Profile Info</h2>
<label>
First Name:
<input v-model="form.firstName" type="text" />
</label>
<label>
Last Name:
<input v-model="form.lastName" type="text" />
</label>
</div>
<!-- Step 3 -->
<div v-if="currentStep === 3">
<h2>Review</h2>
<p><strong>Email:</strong> {{ form.email }}</p>
<p><strong>First Name:</strong> {{ form.firstName }}</p>
<p><strong>Last Name:</strong> {{ form.lastName }}</p>
</div>
<!-- Navigation -->
<div class="actions">
<button type="button" @click="prevStep" :disabled="currentStep === 1">
Back
</button>
<button
v-if="currentStep < totalSteps"
type="button"
@click="nextStep"
>
Next
</button>
<button v-else type="submit">Submit</button>
</div>
<p v-if="error" class="error">{{ error }}</p>
</form>
</template>
<script setup>
import { reactive, ref } from 'vue'
const currentStep = ref(1)
const totalSteps = 3
const error = ref('')
const form = reactive({
email: '',
password: '',
firstName: '',
lastName: '',
})
function validateStep(step) {
error.value = ''
if (step === 1) {
if (!form.email || !form.password) {
error.value = 'Email and password are required.'
return false
}
return true
}
if (step === 2) {
if (!form.firstName || !form.lastName) {
error.value = 'First and last name are required.'
return false
}
return true
}
return true
}
function nextStep() {
if (validateStep(currentStep.value)) {
currentStep.value++
}
}
function prevStep() {
if (currentStep.value > 1) {
currentStep.value--
}
}
function handleSubmit() {
if (!validateStep(currentStep.value)) return
console.log('Form submitted:', form)
alert('Form submitted!')
}
</script>
<style scoped>
.steps {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
}
.steps span.active {
font-weight: bold;
color: blue;
}
.actions {
margin-top: 1rem;
display: flex;
gap: 0.5rem;
}
.error {
color: red;
margin-top: 1rem;
}
</style>
How it works
currentStepdecides which part of the form is visible.formstores all field values across steps.nextStep()checks validation before advancing.prevStep()moves back.handleSubmit()runs on the last step.
Better approach for larger forms
If your form is more complex, consider:
- Splitting each step into its own component
- Using a validation library like:
Vuelidatevee-validate
- Storing form data in Pinia if multiple components need it
- Adding a progress bar or stepper UI
Component-based structure
Example structure:
MultiStepForm.vue
StepOne.vue
StepTwo.vue
StepThree.vue
Parent component handles:
- current step
- shared form data
- navigation
Child components handle:
- their own fields
- step-specific validation
If you want, I can also show:
- a version using Vue 2
- a version using VeeValidate
- a version with separate step components