Skip to content

UttamRahane/vue-form-generator-3

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Vue Form Generator 3

A schema-based form generator component for Vue 3 and Nuxt 3.

This is the Vue 3 / Nuxt 3 compatible version of the popular vue-form-generator library, completely rewritten using Vue 3 Composition API and TypeScript.

πŸš€ Features

  • βœ… Vue 3 & Nuxt 3 Support - Built from ground up for Vue 3 Composition API
  • βœ… Schema-based form generation from JSON
  • βœ… Supports all core field types: input, checkbox, checklist, radios, select, textarea, submit, label, upload
  • βœ… Built-in validation (required, number, string, email, URL, credit card, date, regex, etc.)
  • βœ… Field groups with legends
  • βœ… Dynamic field visibility
  • βœ… Custom validators
  • βœ… Custom field components
  • βœ… TypeScript support
  • βœ… Zero external dependencies
  • βœ… Hot Module Replacement (HMR) for development

πŸ“¦ Installation

Vue 3 Project

npm install vue-form-generator-3
# or
yarn add vue-form-generator-3
# or
pnpm add vue-form-generator-3

Nuxt 3 Project

npm install vue-form-generator-3
# or
yarn add vue-form-generator-3
# or
pnpm add vue-form-generator-3

🎯 Quick Start

Vue 3 - Basic Usage

<template>
  <VueFormGenerator
    :schema="schema"
    :model="model"
    :options="formOptions"
    @model-updated="onModelUpdated"
    @validated="onValidated"
  />
</template>

<script setup>
import { ref } from "vue";
import { VueFormGenerator, schema as schemaUtils, validators } from "vue-form-generator-3";
import "vue-form-generator-3/dist/style.css";

const model = ref({
  name: "",
  email: "",
  age: 25,
});

const formOptions = {
  validateAfterLoad: false,
  validateAfterChanged: true,
};

const schema = {
  fields: [
    {
      type: "input",
      inputType: "text",
      label: "Name",
      model: "name",
      placeholder: "Enter your name",
      required: true,
      validator: ["required", "string"],
    },
    {
      type: "input",
      inputType: "email",
      label: "Email",
      model: "email",
      placeholder: "Enter email",
      required: true,
      validator: ["required", "email"],
    },
    {
      type: "input",
      inputType: "number",
      label: "Age",
      model: "age",
      placeholder: "Enter age",
      min: 18,
      max: 120,
      validator: "number",
    },
    {
      type: "submit",
      buttonText: "Submit",
      validateBeforeSubmit: true,
      onSubmit(model) {
        console.log("Form submitted:", model);
      },
    },
  ],
};

function onModelUpdated(newVal, schema) {
  console.log("Field updated:", schema, newVal);
}

function onValidated(isValid, errors) {
  console.log("Form valid:", isValid, errors);
}
</script>

Vue 3 - Plugin Registration

// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import VueFormGenerator from "vue-form-generator-3";
import "vue-form-generator-3/dist/style.css";

const app = createApp(App);

// Register globally with optional custom validators
app.use(VueFormGenerator, {
  validators: {
    customValidator: (value, field, model) => {
      if (value !== "expected") {
        return ["Value must be 'expected'"];
      }
      return [];
    },
  },
});

app.mount("#app");

Nuxt 3 - Module Registration

Option 1: Using Nuxt Module (Recommended)

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["vue-form-generator-3/src/module"],
  css: ["vue-form-generator-3/dist/style.css"],
});

Option 2: Using Plugin

// plugins/vue-form-generator.ts
import VueFormGenerator from "vue-form-generator-3";

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(VueFormGenerator, {
    validators: {
      // Optional: Add custom validators
    },
  });
});
// nuxt.config.ts
export default defineNuxtConfig({
  css: ["vue-form-generator-3/dist/style.css"],
});

πŸ“– Schema Field Types

Type Component Description
input field-input Text, number, email, password, date, etc.
checkbox field-checkbox Single checkbox
checklist field-checklist Multiple checkbox list
radios field-radios Radio button group
select field-select Dropdown select
textarea field-textarea Multi-line text input
submit field-submit Submit button
label field-label Display-only label
upload field-upload File upload

πŸ”§ Schema Options

Each field in the schema can have:

Common Options

  • type - Field type (required)
  • inputType - For input fields: text, number, email, password, date, etc.
  • label - Field label
  • model - Model property path (e.g., "user.name")
  • placeholder - Placeholder text
  • required - Whether field is required
  • disabled - Whether field is disabled
  • readonly - Whether field is readonly
  • visible - Visibility condition (boolean or function)
  • hint - Hint text below the field
  • help - Help tooltip text
  • validator - Validator(s): function name string or array
  • values - For select, checklist, radios: array of options
  • default - Default value
  • styleClasses - Additional CSS classes
  • onChanged - Change callback
  • onValidated - Validation callback
  • fieldClasses - Additional classes for field wrapper

Input-Specific Options

  • min / max - Min/max values for number/date
  • minlength / maxlength - Text length limits
  • pattern - Regex pattern for validation
  • accept - File types for upload
  • debounceFormatTimeout - Debounce time for formatting

🎨 Advanced Examples

Field Groups

const schema = {
  groups: [
    {
      legend: "Personal Information",
      fields: [
        {
          type: "input",
          inputType: "text",
          label: "First Name",
          model: "firstName",
          required: true,
        },
        {
          type: "input",
          inputType: "text",
          label: "Last Name",
          model: "lastName",
          required: true,
        },
      ],
    },
    {
      legend: "Contact Details",
      fields: [
        {
          type: "input",
          inputType: "email",
          label: "Email",
          model: "email",
          validator: "email",
        },
        {
          type: "input",
          inputType: "tel",
          label: "Phone",
          model: "phone",
        },
      ],
    },
  ],
};

Dynamic Field Visibility

const schema = {
  fields: [
    {
      type: "input",
      inputType: "text",
      label: "Company Name",
      model: "company",
      visible: (model, field, form) => {
        return model.hasCompany === true;
      },
    },
    {
      type: "checkbox",
      label: "I have a company",
      model: "hasCompany",
    },
  ],
};

Custom Validators

import { VueFormGenerator } from "vue-form-generator-3";

app.use(VueFormGenerator, {
  validators: {
    phoneNumber(value, field, model) {
      if (!value) return [];
      const phoneRegex = /^[0-9]{10}$/;
      if (!phoneRegex.test(value)) {
        return ["Invalid phone number. Must be 10 digits."];
      }
      return [];
    },
    
    passwordStrength(value, field, model) {
      if (!value) return [];
      const errors = [];
      if (value.length < 8) {
        errors.push("Password must be at least 8 characters");
      }
      if (!/[A-Z]/.test(value)) {
        errors.push("Password must contain uppercase letter");
      }
      if (!/[0-9]/.test(value)) {
        errors.push("Password must contain a number");
      }
      return errors;
    },
  },
});

// Use in schema
const schema = {
  fields: [
    {
      type: "input",
      inputType: "tel",
      label: "Phone",
      model: "phone",
      validator: "phoneNumber",
    },
    {
      type: "input",
      inputType: "password",
      label: "Password",
      model: "password",
      validator: "passwordStrength",
    },
  ],
};

πŸ› οΈ Custom Fields

Creating a Custom Field Component

Create a new Vue component with the following structure:

<!-- CustomField.vue -->
<template>
  <div class="custom-field-wrapper">
    <label :for="getFieldID(schema)">
      {{ schema.label }}
    </label>
    <div class="field-content">
      <input
        :id="getFieldID(schema)"
        :value="value.get()"
        @input="onInput"
        :disabled="disabled"
        class="custom-input"
      />
    </div>
    <div v-if="fieldErrors(schema).length > 0" class="errors">
      <span v-for="error in fieldErrors(schema)" :key="error">
        {{ error }}
      </span>
    </div>
  </div>
</template>

<script setup lang="ts">
import { getCurrentInstance } from "vue";
import { useAbstractField } from "vue-form-generator-3";

const props = defineProps({
  vfg: Object,
  model: Object,
  schema: Object,
  formOptions: Object,
  disabled: Boolean,
});

const emit = defineEmits(["model-updated", "validated"]);

const instance = getCurrentInstance();
const { value, validate, clearValidationErrors, getFieldID, getFieldClasses, updateModelValue } = useAbstractField(
  props,
  emit,
  instance
);

const onInput = (event: Event) => {
  const target = event.target as HTMLInputElement;
  updateModelValue(target.value, value.get());
};

const fieldErrors = (schema: any) => {
  // Access errors from parent or manage locally
  return [];
};

defineExpose({ validate, clearValidationErrors });
</script>

<style scoped>
.custom-field-wrapper {
  margin-bottom: 1rem;
}
.custom-input {
  width: 100%;
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
}
.errors {
  color: red;
  font-size: 0.875em;
  margin-top: 0.25rem;
}
</style>

Registering Custom Fields in Vue 3

// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import VueFormGenerator, { registerFieldComponent } from "vue-form-generator-3";
import CustomField from "./components/CustomField.vue";

const app = createApp(App);

// Register the plugin
app.use(VueFormGenerator);

// Register custom field component
registerFieldComponent("custom-field", CustomField);

app.mount("#app");

Registering Custom Fields in Nuxt 3

// plugins/vue-form-generator.ts
import { registerFieldComponent } from "vue-form-generator-3";
import CustomField from "~/components/CustomField.vue";

export default defineNuxtPlugin((nuxtApp) => {
  // Register custom field
  registerFieldComponent("custom-field", CustomField);
});
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["vue-form-generator-3/src/module"],
  css: ["vue-form-generator-3/dist/style.css"],
});

Using Custom Fields

const schema = {
  fields: [
    {
      type: "custom-field", // Use your custom field type
      label: "Custom Input",
      model: "customValue",
      placeholder: "Enter custom value",
    },
  ],
};

πŸƒ Running the Example

This library includes a playground/example that demonstrates all features:

# Install dependencies
npm install

# Run development server
npm run dev

# Open browser to http://localhost:5173/

The playground includes:

  • All field types (input, select, checkbox, radios, textarea, submit)
  • Form validation with built-in validators
  • Model updates and validation events
  • Field groups with legends
  • Dynamic field visibility
  • Custom styling examples

πŸ—οΈ Building for Production

# Build the library
npm run build

# Output files in dist/:
# - vue-form-generator-3.js (ES module, 41KB)
# - vue-form-generator-3.umd.cjs (UMD, 32KB)
# - style.css (6KB)

πŸ“š API Reference

Components

<VueFormGenerator>

Main form generator component.

Props:

  • schema (Object) - Form schema definition
  • model (Object) - Form data model
  • options (Object) - Form options
  • multiple (Boolean) - Enable multiple mode
  • isNewModel (Boolean) - Mark as new model

Events:

  • @model-updated(newVal, schema) - Fired when any field value changes
  • @validated(isValid, errors, vfg) - Fired after validation

Methods (via ref):

  • validate() - Validate all fields
  • clearValidationErrors() - Clear all validation errors

<FormGroup>

Wrapper component for each field (used internally).

Utilities

schema

Schema utility functions.

import { schema } from "vue-form-generator-3";

// Available utilities
schema.slugifyFormID(schema, prefix); // Generate field ID

validators

Built-in validator functions.

import { validators } from "vue-form-generator-3";

// Available validators
validators.required;
validators.number;
validators.integer;
validators.double;
validators.string;
validators.array;
validators.date;
validators.regexp;
validators.email;
validators.url;
validators.creditCard;
validators.alpha;
validators.alphaNumeric;

registerFieldComponent(name, component)

Register a custom field component.

import { registerFieldComponent } from "vue-form-generator-3";
import MyCustomField from "./MyCustomField.vue";

registerFieldComponent("my-custom", MyCustomField);

πŸ”„ Migration from vue-form-generator (Vue 2)

If you're migrating from the original vue-form-generator for Vue 2:

Key Changes

  1. Composition API - All components now use <script setup> syntax
  2. TypeScript - Full TypeScript support with type definitions
  3. No lodash dependency - Built-in utility functions
  4. Vue 3 reactivity - Uses Vue 3's reactive system
  5. Nuxt 3 module - Native Nuxt 3 support

Schema Compatibility

Most schema definitions work as-is. Key differences:

  • Component registration uses registerFieldComponent() instead of Vue 2 plugin system
  • Event handling uses Vue 3 emit syntax
  • Custom validators receive same parameters

Example Migration

Before (Vue 2):

import VueFormGenerator from "vue-form-generator";

Vue.use(VueFormGenerator);

After (Vue 3):

import { createApp } from "vue";
import VueFormGenerator from "vue-form-generator-3";

const app = createApp(App);
app.use(VueFormGenerator);

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

πŸ“„ License

MIT

πŸ”— Links

πŸ™ Acknowledgments

This library is a Vue 3 / Nuxt 3 port of the original vue-form-generator library. Thanks to all contributors of the original project.

About

Built a schema-driven form generator for Vue 3/Nuxt 3 with validation + dynamic fields

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors