@gooonzick/wizard-vue
v1.12.0
Published
Vue 3 integration for Wizard framework
Maintainers
Readme
@gooonzick/wizard-vue
Vue 3 Composition API integration for the Wizard framework.
Features
- Vue 3 Composable -
useWizard()composable with reactiveComputedRefvalues - Organized API - State grouped into logical slices (state, validation, navigation, loading, actions)
- Navigation History -
canGoBackandstepHistoryfor history-based back navigation - Granular Composables - Fine-grained subscriptions with
useWizardData(),useWizardNavigation(), etc. - v-model Support -
useWizardField()for writable computed refs - Optional Provider -
WizardProviderfor sharing state via provide/inject - Full Type Safety - TypeScript generics for your data types
Installation
npm install @gooonzick/wizard-vue @gooonzick/wizard-core
# or
pnpm add @gooonzick/wizard-vue @gooonzick/wizard-core
# or
yarn add @gooonzick/wizard-vue @gooonzick/wizard-coreQuick Start
Basic Usage with Composition API
<script setup lang="ts">
import { useWizard } from "@gooonzick/wizard-vue";
import { createLinearWizard } from "@gooonzick/wizard-core";
interface FormData {
name: string;
email: string;
age: number;
}
const definition = createLinearWizard<FormData>({
id: "my-wizard",
steps: [
{ id: "personal", title: "Personal Info" },
{ id: "contact", title: "Contact" },
{ id: "review", title: "Review" },
],
});
const { state, navigation, loading, actions } = useWizard({
definition,
initialData: { name: "", email: "", age: 0 },
});
</script>
<template>
<div>
<h2>{{ state.currentStep.value?.title }}</h2>
<div v-if="state.currentStepId.value === 'personal'">
<input
:value="state.data.value.name"
@input="
actions.updateField('name', ($event.target as HTMLInputElement).value)
"
placeholder="Name"
/>
</div>
<div v-else-if="state.currentStepId.value === 'contact'">
<input
:value="state.data.value.email"
@input="
actions.updateField(
'email',
($event.target as HTMLInputElement).value,
)
"
placeholder="Email"
/>
</div>
<div v-else-if="state.currentStepId.value === 'review'">
<p>Name: {{ state.data.value.name }}</p>
<p>Email: {{ state.data.value.email }}</p>
</div>
<button
@click="navigation.goPrevious"
:disabled="!navigation.canGoPrevious.value"
>
Previous
</button>
<!-- On the last step goNext() completes the wizard; canGoNext is false there. -->
<button
@click="navigation.goNext()"
:disabled="loading.isNavigating.value"
>
{{ navigation.isLastStep.value ? "Finish" : "Next" }}
</button>
</div>
</template>Using WizardProvider for Shared State
<!-- App.vue -->
<script setup lang="ts">
import { WizardProvider } from "@gooonzick/wizard-vue";
import { createLinearWizard } from "@gooonzick/wizard-core";
import WizardSteps from "./WizardSteps.vue";
import WizardNavigation from "./WizardNavigation.vue";
const definition = createLinearWizard({
id: "my-wizard",
steps: [
{ id: "step1", title: "Step 1" },
{ id: "step2", title: "Step 2" },
],
});
</script>
<template>
<WizardProvider :definition="definition" :initialData="{ name: '' }">
<WizardSteps />
<WizardNavigation />
</WizardProvider>
</template><!-- WizardSteps.vue -->
<script setup lang="ts">
import { useWizardData, useWizardActions } from "@gooonzick/wizard-vue";
const { currentStepId, data } = useWizardData();
const { updateField } = useWizardActions();
</script>
<template>
<div>
<h2>Current: {{ currentStepId.value }}</h2>
<input
:value="data.value.name"
@input="updateField('name', $event.target.value)"
/>
</div>
</template><!-- WizardNavigation.vue -->
<script setup lang="ts">
import { useWizardLoading, useWizardNavigation } from "@gooonzick/wizard-vue";
const { canGoPrevious, isLastStep, goNext, goPrevious } = useWizardNavigation();
const { isNavigating } = useWizardLoading();
</script>
<template>
<!-- Top-level refs are auto-unwrapped in the template: no .value here -->
<div>
<button @click="goPrevious()" :disabled="!canGoPrevious || isNavigating">
Previous
</button>
<!-- On the last step goNext() completes the wizard; canGoNext is false there. -->
<button @click="goNext()" :disabled="isNavigating">
{{ isLastStep ? "Finish" : "Next" }}
</button>
</div>
</template>API Reference
Composables
useWizard(options)
Main composable for wizard state management. Returns organized state slices.
Parameters:
definition: WizardDefinition<T>- Wizard configurationinitialData: T- Initial form datacontext?: WizardContext- Optional context for validators/hooksonStateChange?: (state) => void- State change callbackonStepEnter?: (stepId, data) => void- Step enter callbackonStepLeave?: (stepId, data) => void- Step leave callbackonComplete?: (data) => void- Completion callbackonCancel?: (data) => void | Promise<void>- Cancel callbackonReset?: () => void- Reset callbackonError?: (error) => void- Error callbackplugins?: WizardPlugin<T>[]- Reference-stable plugins (read once at setup)
Returns:
state- Current step, data,stepStatuses,progress(ComputedRefs)validation- Validation state and errorsnavigation- Navigation state and methods (goPrevious,goTo, …)loading- Async operation states (isValidating,isSubmitting,isNavigating,isLoadingStep)actions- Data mutations,validate/validateAll,submit,reset/cancel,serialize/restore,preloadStep
Granular Composables (require WizardProvider)
useWizardData<T>()- State slice onlyuseWizardNavigation()- Navigation slice onlyuseWizardValidation()- Validation slice onlyuseWizardLoading()- Loading slice onlyuseWizardActions<T>()- Actions slice only (validateAll,cancel, …)useWizardField(wizard, field)oruseWizardField(field)inside Provider -v-modelbindingcreateTypedWizardProvider<T>()- Pre-typed Provider + granular helpers
Components
WizardProvider
Provider component for sharing wizard state via provide/inject.
Props: Same as useWizard options, plus children
TypeScript Support
All composables and components are fully typed with TypeScript generics:
interface MyFormData {
name: string;
email: string;
}
const { state, actions } = useWizard<MyFormData>({
definition,
initialData: { name: "", email: "" },
});
// TypeScript knows the shape of data
actions.updateField("name", "John"); // ✓ OK
actions.updateField("invalid", "value"); // ✗ ErrorLicense
MIT
