Skip to content

TheOluwafemi/vue-form-manager

Repository files navigation

Vue Form Manager

npm version npm downloads GitHub license GitHub stars

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.

πŸ“‹ Table of Contents

✨ Features

  • 🎯 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

πŸ“¦ Installation

# npm
npm install vue-form-manager

# yarn
yarn add vue-form-manager

# pnpm
pnpm add vue-form-manager

Requirements

  • Vue 3.x
  • Node.js β‰₯ 20.0.0

πŸš€ Quick Start

<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>

πŸ“š Complete Field Type Guide

πŸ”€ String Fields

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',
  },
})

πŸ“§ Email Fields

const { schema, initialValues } = createSchema({
  email: {
    type: 'email',
    required: 'Email address is required',
    emailError: 'Please enter a valid email address',
  },
})

πŸ”’ Number Fields

const { schema, initialValues } = createSchema({
  age: {
    type: 'number',
    required: 'Age is required',
    initialValue: 18,
  },
})

🌐 URL Fields

const { schema, initialValues } = createSchema({
  website: {
    type: 'url',
    required: 'Website URL is required',
    urlError: 'Please enter a valid URL',
  },
})

πŸ“… Date Fields

const { schema, initialValues } = createSchema({
  birthDate: {
    type: 'date',
    required: 'Birth date is required',
    initialValue: null,
  },
})

βœ… Boolean Fields

const { schema, initialValues } = createSchema({
  agreeToTerms: {
    type: 'boolean',
    required: 'You must agree to terms',
    initialValue: false,
  },
})

πŸ“‹ Enum Fields (Select/Dropdown)

const { schema, initialValues } = createSchema({
  role: {
    type: 'enum',
    values: ['admin', 'editor', 'viewer'],
    required: 'Please select a role',
  },
})

πŸ“¦ Array Fields

const { schema, initialValues } = createSchema({
  tags: {
    type: 'array',
    initialValue: ['javascript', 'vue'],
  },
})

// Usage: Add/remove items dynamically
const addTag = (newTag) => {
  setFieldValue('tags', [...form.tags.value, newTag])
}

πŸ—οΈ Object Fields (Nested)

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',
      },
    },
  },
})

πŸ› οΈ API Reference

createSchema(config)

Creates validation schema and initial values.

Parameters:

  • config: Record<string, FieldConfig> - Field configuration object

Returns:

  • { schema: ZodObject, initialValues: Record<string, any> }

useForm({ schema, initialValues })

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
}

πŸ“ Field Configuration

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
}

πŸ”· TypeScript Support

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 })

🎯 Best Practices

  1. Consistent Error Messages: Use clear, user-friendly validation messages
  2. Validation Timing: Use @blur for validation, @input for clearing errors
  3. TypeScript: Type your configurations for better development experience
  4. Form Organization: Group related fields logically

🀝 Contributing

  1. Fork the repository
  2. Create your feature branch: git checkout -b feat/amazing-feature
  3. Commit your changes: git commit -m 'feat: add amazing feature'
  4. Push to the branch: git push origin feat/amazing-feature
  5. Open a Pull Request

Commit Convention

This project uses Conventional Commits:

  • feat: - New features
  • fix: - Bug fixes
  • docs: - Documentation changes
  • style: - Code style changes
  • refactor: - Code refactoring
  • test: - Test updates
  • chore: - Maintenance tasks

πŸ“„ License

MIT License - see the LICENSE file for details.

⭐ Show Your Support

If this project helped you, please consider giving it a ⭐ on GitHub!