A simple, powerful form validation library for Vue 3 that makes form handling effortless. Define your validation rules in plain JavaScript objects and let the library handle your state and the complex validation logic behind the scenes.
Perfect for: Vue 3 applications that need robust form validation without the complexity of learning Zod schemas directly.
- Features
- Installation
- Quick Start
- Field Types Guide
- API Reference
- TypeScript Support
- Best Practices
- Testing
- Contributing
- License
- π― Declarative Schema Definition: Define validation rules using simple configuration objects
- π· TypeScript Support: Full type safety with excellent IntelliSense
- βοΈ Vue 3 Native: Built with Composition API for seamless integration
- π« Zero Zod Knowledge Required: Abstract away complex Zod syntax
- π Reactive State Management: Real-time form state with Vue's reactivity
- π Comprehensive Field Types: Support for all common form field types
- β Flexible Validation: Field-level and form-level validation with custom messages
- π Production Ready: Robust error handling and edge case management
- β‘ Lightweight: Powered by Zod under the hood for reliable validation
# npm
npm install vue-form-manager
# yarn
yarn add vue-form-manager
# pnpm
pnpm add vue-form-manager
- Vue 3.x
- Node.js β₯ 20.0.0
<template>
<form @submit.prevent="handleSubmit">
<input
v-model="form.name.value"
@input="handleInput('name')"
@blur="handleBlur('name')"
placeholder="Full Name" />
<span
v-if="form.name.error"
class="error"
>{{ form.name.error }}</span
>
<button
type="submit"
:disabled="formHasErrors">
Submit
</button>
</form>
</template>
<script setup>
import { useForm, createSchema } from 'vue-form-manager'
const { schema, initialValues } = createSchema({
name: {
type: 'string',
required: 'Name is required',
min: 2,
minError: 'Name must be at least 2 characters',
},
})
const {
form,
formHasErrors,
handleInput,
handleBlur,
validateForm,
getFormData,
} = useForm({
schema,
initialValues,
})
const handleSubmit = () => {
if (validateForm()) {
console.log('Form is valid!', getFormData())
}
}
</script>
const { schema, initialValues } = createSchema({
username: {
type: 'string',
required: 'Username is required',
min: 3,
minError: 'Username must be at least 3 characters',
max: 20,
maxError: 'Username cannot exceed 20 characters',
},
})
const { schema, initialValues } = createSchema({
email: {
type: 'email',
required: 'Email address is required',
emailError: 'Please enter a valid email address',
},
})
const { schema, initialValues } = createSchema({
age: {
type: 'number',
required: 'Age is required',
initialValue: 18,
},
})
const { schema, initialValues } = createSchema({
website: {
type: 'url',
required: 'Website URL is required',
urlError: 'Please enter a valid URL',
},
})
const { schema, initialValues } = createSchema({
birthDate: {
type: 'date',
required: 'Birth date is required',
initialValue: null,
},
})
const { schema, initialValues } = createSchema({
agreeToTerms: {
type: 'boolean',
required: 'You must agree to terms',
initialValue: false,
},
})
const { schema, initialValues } = createSchema({
role: {
type: 'enum',
values: ['admin', 'editor', 'viewer'],
required: 'Please select a role',
},
})
const { schema, initialValues } = createSchema({
tags: {
type: 'array',
initialValue: ['javascript', 'vue'],
},
})
// Usage: Add/remove items dynamically
const addTag = (newTag) => {
setFieldValue('tags', [...form.tags.value, newTag])
}
const { schema, initialValues } = createSchema({
address: {
type: 'object',
schema: {
street: { type: 'string', required: 'Street required' },
city: { type: 'string', required: 'City required' },
zipCode: {
type: 'string',
required: 'ZIP required',
min: 5,
minError: 'ZIP must be at least 5 characters',
},
},
},
})
Creates validation schema and initial values.
Parameters:
config: Record<string, FieldConfig>
- Field configuration object
Returns:
{ schema: ZodObject, initialValues: Record<string, any> }
Returns form state and management functions:
{
// State
form: FormState // Reactive form fields
formError: Ref<string> // General form error
isSubmitting: Ref<boolean> // Loading state
formHasErrors: ComputedRef<boolean> // Has validation errors
formHasChanges: ComputedRef<boolean> // Form modified
// Methods
setFieldValue: (field, value) => void
setFieldError: (field, error) => void
handleInput: (field) => void // Mark touched, clear errors
handleBlur: (field) => void // Validate on blur
validateForm: () => boolean // Validate entire form
validateField: (field) => boolean // Validate single field
getFormData: () => object // Get clean values
getFormErrors: () => object // Get all current errors
getFormErrorsWithValidation: () => object // Get errors after validation
hasErrors: () => boolean // Check validation state
hasChanges: () => boolean // Check if modified
resetForm: () => void // Reset to initial
}
interface FieldConfig {
type:
| 'string'
| 'email'
| 'number'
| 'boolean'
| 'date'
| 'url'
| 'enum'
| 'array'
| 'object'
required?: string // Required error message
min?: number // Min length/value
minError?: string // Min error message
max?: number // Max length/value
maxError?: string // Max error message
emailError?: string // Email error message
urlError?: string // URL error message
values?: string[] // Enum values (required for enum type)
initialValue?: any // Default value
schema?: FieldConfig | { [key: string]: FieldConfig } // Nested validation
}
The library is fully typed with TypeScript. Import types for better development experience:
import {
useForm,
createSchema,
type FieldConfig,
type UseFormReturn,
} from 'vue-form-manager'
// Type your schema configuration
const schemaConfig: Record<string, FieldConfig> = {
username: {
type: 'string',
required: 'Username is required',
min: 3,
minError: 'Too short',
},
}
// Get full type inference
const { schema, initialValues } = createSchema(schemaConfig)
const formControls: UseFormReturn = useForm({ schema, initialValues })
- Consistent Error Messages: Use clear, user-friendly validation messages
- Validation Timing: Use
@blur
for validation,@input
for clearing errors - TypeScript: Type your configurations for better development experience
- Form Organization: Group related fields logically
- Fork the repository
- Create your feature branch:
git checkout -b feat/amazing-feature
- Commit your changes:
git commit -m 'feat: add amazing feature'
- Push to the branch:
git push origin feat/amazing-feature
- Open a Pull Request
This project uses Conventional Commits:
feat:
- New featuresfix:
- Bug fixesdocs:
- Documentation changesstyle:
- Code style changesrefactor:
- Code refactoringtest:
- Test updateschore:
- Maintenance tasks
MIT License - see the LICENSE file for details.
If this project helped you, please consider giving it a β on GitHub!