DEV Community

Parsa Jiravand
Parsa Jiravand

Posted on

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

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

Top comments (0)