vue3-form-wizard
v1.1.1
Published
vue3-form-wizard is a vue based component with no external depenendcies which simplifies tab wizard management.
Maintainers
Readme
Vue3 form wizard
A dynamic wizard to split your forms easier
Vue3-form-wizard is a vue based component with no external depenendcies which simplifies tab wizard management.
**📚Document ・ 🔎 Demos ・ 🔬 Playground**
Dependencies
- required: Vuejs >= 3.x
Installation
npm install vue3-form-wizard --saveyarn add vue3-form-wizard🚀 Features
- Schema mode: Declarative steps with
schema,condition,validate, andv-model - Classic mode: Slot-based steps with
<tab-content> - Vue Router: URL sync with
routeprop (optional) - Accessibility: ARIA roles, keyboard navigation
- TypeScript: Full type support
🔧 Document
Quick start
<script setup>
import { FormWizard, TabContent } from 'vue3-form-wizard'
import 'vue3-form-wizard/dist/style.css'
const onComplete = () => alert('Done!')
</script>
<template>
<form-wizard @on-complete="onComplete" color="#9b59b6">
<tab-content title="Step 1">
<p>First step content.</p>
</tab-content>
<tab-content title="Step 2">
<p>Second step content.</p>
</tab-content>
<tab-content title="Step 3">
<p>Final step.</p>
</tab-content>
</form-wizard>
</template>Register globally or use components locally; include the CSS. See Schema mode and Router Integration for more.
🔗 Router Integration
Vue3 Form Wizard now supports automatic route synchronization with Vue Router!
Setup
First, install Vue Router:
npm install [email protected]Configure your Vue app with Vue Router:
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from './App.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
// Your routes
]
})
const app = createApp(App)
app.use(router)
app.mount('#app')Usage
Add route prop to your tab-content components:
<template>
<form-wizard @on-complete="onComplete" color="#9b59b6">
<tab-content title="Step 1" route="/step1">
Content for step 1
</tab-content>
<tab-content title="Step 2" route="/step2">
Content for step 2
</tab-content>
<tab-content title="Step 3" route="/step3">
Content for step 3
</tab-content>
</form-wizard>
</template>Features
- ✅ Automatic Navigation: Tab changes update the URL
- ✅ URL Sync: Direct URL access navigates to the correct tab
- ✅ Browser History: Back/forward buttons work correctly
- ✅ Deep Linking: Shareable URLs for specific wizard steps
Route Types
The route prop accepts:
- String:
route="/step1"- Direct path - Object:
route="{ name: 'step1', params: { id: 1 } }"- Named routes with params
Schema Mode
Define wizard steps declaratively with conditions and validation:
<template>
<FormWizard
title="Schema: Basic"
:schema="schema"
:schema-components="schemaComponents"
v-model="schemaData"
@on-complete="onComplete"
/>
</template>
<script setup>
import { ref } from "vue";
import { FormWizard } from "vue3-form-wizard";
import "vue3-form-wizard/dist/style.css";
import SimpleStep from "./schema-steps/SimpleStep.vue";
import DoneStep from "./schema-steps/DoneStep.vue";
const schema = {
initialData: { plan: "basic" },
steps: [
{ id: "intro", title: "Intro", component: "SimpleStep" },
{ id: "review", title: "Review", component: "DoneStep" },
],
};
const schemaComponents = { SimpleStep, DoneStep };
const schemaData = ref();
const onComplete = () => alert("Done!");
</script>
Schema mode with DefineComponent
<template>
<FormWizard
title="Schema: defineComponent"
:schema="schema"
:schema-components="schemaComponents"
v-model="schemaData"
color="#8e44ad"
@on-complete="onComplete"
/>
</template>
<script setup>
import { ref, defineComponent, h } from "vue";
import { FormWizard } from "vue3-form-wizard";
import "vue3-form-wizard/dist/style.css";
// Step components using defineComponent with setup returning render function
const NameStep = defineComponent({
name: "NameStep",
props: {
data: { type: Object, required: true },
updateData: { type: Function, required: true },
},
setup(props) {
return () =>
h("div", [
h("h2", "Your name"),
h("input", {
type: "text",
value: props.data.name,
placeholder: "Name",
onInput: (e) => props.updateData({ name: e.target.value }),
style: "padding:8px;width:100%;max-width:240px;margin-bottom:8px;",
}),
]);
},
});
const SummaryStep = defineComponent({
name: "SummaryStep",
props: {
data: { type: Object, required: true },
updateData: { type: Function, required: true },
},
setup(props) {
return () =>
h("div", [
h("h2", "Summary"),
h("p", ["Hello, ", h("strong", props.data.name || "Guest"), "!"]),
]);
},
});
const schema = {
initialData: { name: "" },
steps: [
{ id: "name", title: "Name", component: "NameStep" },
{ id: "summary", title: "Summary", component: "SummaryStep" },
],
};
const schemaComponents = { NameStep, SummaryStep };
const schemaData = ref({ name: "" });
const onComplete = () => alert("Done!");
</script>
Step components receive data and update-data props. Use condition to hide steps dynamically and validate to block navigation.
RTL support
You can enable RTL for the wizard content without flipping the steps:
If you also want the horizontal steps, progress bar, and footer buttons to run from right to left, use reverse-horizontal and rtl together.
Sample Demo: RTL support
Local Samples & Tests
Run the dev server for 15 samples:
npm run devVisit http://localhost:5173 and use the dropdown to switch between samples: basic wizard, icons, layouts, shapes, validation, schema mode, and more.
Run tests:
npm run testScripts
| Command | Description |
| --------------- | ----------------------------- |
| npm run dev | Start dev server with samples |
| npm run build | Build library and types |
| npm run test | Run Vitest test suite |
Credits
Cloned from vue-form-wizard, updated to Vue 3 with new features and bug fixes.
