๐Ÿš€ Build a Schema-Based Wizard Form in Vue 3 (No Templates Needed)

Parsa Jiravand

Parsa Jiravand

2026-03-19T20:40:16Z

3 min read

If you've ever built multi-step forms in Vue, you know the usual pain:

  • Managing step state manually
  • Handling validation across steps
  • Conditionally showing steps
  • Keeping everything in sync

What if you could define your entire wizard in a single object?

With vue3-form-wizard v1, you can do exactly that using the new Schema Mode.


โœจ What is Schema Mode?

Schema Mode is a declarative API that lets you build a multi-step wizard without writing <tab-content> components.

Instead, you define everything like this:

  • Steps
  • Conditions
  • Validation
  • Data structure

๐Ÿ‘‰ All inside one schema object.


๐Ÿง  Why Use Schema Mode?

  • ๐Ÿงฉ Centralized configuration
  • ๐Ÿ” Reactive step conditions
  • โœ… Built-in validation per step
  • ๐Ÿ”„ Shared state across all steps
  • โšก Faster development (less boilerplate)

๐Ÿ“ฆ Installation

npm install vue3-form-wizard
Enter fullscreen mode Exit fullscreen mode

๐Ÿ— Basic Example

Letโ€™s build a simple 2-step wizard:

<template>
  <form-wizard
    :schema="schema"
    :schema-components="schemaComponents"
    v-model="wizardData"
    @on-complete="handleComplete"
  />
</template>

<script setup>
import { ref } from 'vue'
import { FormWizard } from 'vue3-form-wizard'
import 'vue3-form-wizard/dist/style.css'

import IntroStep from './IntroStep.vue'
import ReviewStep from './ReviewStep.vue'

const schema = {
  initialData: { plan: 'basic' },
  steps: [
    { id: 'intro', title: 'Intro', component: 'IntroStep' },
    { id: 'review', title: 'Review', component: 'ReviewStep' },
  ],
}

const schemaComponents = { IntroStep, ReviewStep }

const wizardData = ref({ plan: 'basic' })

const handleComplete = () => {
  alert('Done!')
}
</script>
Enter fullscreen mode Exit fullscreen mode

๐Ÿงฉ How It Works

1. initialData โ†’ Your Single Source of Truth

initialData: {
  plan: 'basic',
  email: ''
}
Enter fullscreen mode Exit fullscreen mode

All steps read and update this shared object.


2. Steps Configuration

steps: [
  { id: 'plan', title: 'Plan', component: 'PlanStep' },
  { id: 'contact', title: 'Contact', component: 'ContactStep' },
]
Enter fullscreen mode Exit fullscreen mode

Each step is just metadata โ€” no template nesting required.


๐Ÿ”„ Two-Way Data Binding in Steps

Each step receives:

  • data โ†’ current wizard state
  • updateData() โ†’ function to update state

Example:

<script setup>
defineProps(['data', 'updateData'])

const onChange = (e) => {
  updateData({ plan: e.target.value })
}
</script>
Enter fullscreen mode Exit fullscreen mode

๐ŸŽฏ Conditional Steps (Dynamic Flow)

Want to show steps based on user input?

{
  id: 'premium',
  title: 'Premium',
  component: 'PremiumStep',
  condition: ({ data }) => data.plan === 'premium'
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ‘‰ This step only appears if the user selects premium plan.


โœ… Validation (Sync + Async)

You can block navigation easily:

{
  id: 'email',
  title: 'Email',
  component: 'EmailStep',
  validate: ({ data }) => {
    const valid = /^[^@]+@[^@]+\.\w+$/.test(data.email || '')
    return valid ? true : 'Enter a valid email'
  }
}
Enter fullscreen mode Exit fullscreen mode
  • true โ†’ allow navigation
  • string โ†’ show error message

โšก Advanced: Define Steps Without .vue Files

You can even define steps inline using defineComponent:

const NameStep = defineComponent({
  props: ['data', 'updateData'],
  setup(props) {
    return () => h('input', {
      value: props.data.name,
      onInput: e => props.updateData({ name: e.target.value })
    })
  }
})
Enter fullscreen mode Exit fullscreen mode

๐Ÿ‘‰ Perfect for dynamic or generated UIs.


๐Ÿ” Full Example (Minimal)

const schema = {
  initialData: { name: '' },
  steps: [
    { id: 'name', title: 'Name', component: 'NameStep' },
    { id: 'summary', title: 'Summary', component: 'SummaryStep' },
  ]
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ†š Schema Mode vs Classic Mode

Feature Schema Mode Classic Mode
Config-driven โœ… โŒ
Dynamic steps โœ… โš ๏ธ manual
Clean structure โœ… โŒ
Flexibility โœ… โœ…

๐ŸŽ‰ Final Thoughts

Schema Mode turns multi-step forms into a data problem instead of a UI problem.

Instead of juggling components and state, you:

๐Ÿ‘‰ Define everything once
๐Ÿ‘‰ Let the wizard handle the rest


๐Ÿ”— Resources


๐Ÿ’ฌ What Do You Think?

Would you use schema-driven forms in your projects?

Or do you prefer full control with traditional components?

Let me know in the comments ๐Ÿ‘‡


๐Ÿท Tags

vue #vue3 #javascript #frontend #webdev #opensource #ui #forms #developer-tools #npm