UNPKG

@jubayer11/vue-dynamic-form-builder

Version:

Vue 3 schema-driven dynamic form builder with flexible validation, styling, and real-world use case demos.

859 lines (606 loc) β€’ 26.7 kB
# Vue Dynamic Form Builder ![Vue 3 Compatible](https://img.shields.io/badge/Vue%203-Compatible-%23349b43) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE) ![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg) [![Live Demo](https://img.shields.io/badge/Demo-Live%20Now-brightgreen)](https://jubayer11.github.io/vue-dynamic-form-builder/) [![npm](https://img.shields.io/npm/v/@jubayer11/vue-dynamic-form-builder)](https://www.npmjs.com/package/@jubayer11/vue-dynamic-form-builder) [![GitHub](https://img.shields.io/github/stars/jubayer11/vue-dynamic-form-builder?style=social)](https://github.com/jubayer11/vue-dynamic-form-builder) [![Related Package](https://img.shields.io/badge/Also%20Check-Vue%20Dynamic%20Table%20Builder-orange)](https://www.npmjs.com/package/@jubayer11/vue-dynamic-table-builder) <!-- Divider after badges --> --- ## Build fully customizable, schema-driven forms β€” with complete developer freedom. Vue Dynamic Form Builder gives you the tools to create fully dynamic, validated, and beautifully styled forms β€” while keeping total control over structure, behavior, layout, and appearance. It’s built to empower developers who want flexibility beyond typical rigid form builders. <!-- Divider after intro paragraph --> --- ## πŸš€ Why Use Vue Dynamic Form Builder? - **True Flexibility:** Full control over structure, fields, validation, styling, and submission logic β€” not tied to rigid presets. - **Schema-Driven:** Define your entire form β€” fields, layouts, validations β€” using simple JavaScript objects. No repetitive HTML or template duplication. - **Lightweight and Clean:** No bulky UI frameworks. Built purely with Vue 3 Composition API and clean, extensible CSS utilities. - **Fully Extensible:** Easily add new field types, create custom validation rules, and inject your own UI components if needed. - **Manual or Auto Submission:** Decide whether the form handles submit automatically β€” or give yourself full manual control over when and how it submits. - **Frontend-Agnostic:** Designed to adapt easily to any backend API and frontend system β€” with no assumptions about your stack or styling. <!-- Divider after Why Use --> --- ## πŸ—οΈ Internal Structure Overview Vue Dynamic Form Builder is built with a lightweight, highly modular internal architecture to maximize flexibility and developer control. It uses a **schema-driven approach**: You define your form structure using JavaScript objects (`CustomizableTextField` + `FieldType`), and the form renders itself automatically based on that schema. --- ### πŸ”Ή Core Components | Part | Purpose | |:---|:---| | **CustomizableTextField** | Master class that manages the full form: adds fields, controls submit button, handles global styles, collects backend errors. | | **FieldType** | Blueprint for each individual field (e.g., text, textarea, select, radio, multi-select, password, date picker). Defines label, placeholder, validations, custom styles, etc. | | **ValidationSetup** | Utility to easily attach built-in and custom validations declaratively to fields. | | **DynamicForm.vue** | The main engine: dynamically renders the form from the schema, connects Vuelidate for live validation, manages form state and submission. | | **textFieldStyle** | Global default styling system for inputs, labels, errors, and wrappers. Can be overridden globally, per-form, or per-field. | --- ### πŸ”Ή Internal Utilities and Libraries | Utility | Purpose | |:---|:---| | **Vuelidate** | Used internally to power all validation logic dynamically. No manual Vuelidate setup needed by the user. | | **Moment.js** | Used for formatting and parsing dates and times inside `datePickerField` inputs. | | **Lodash (isEqual)** | Used to deeply compare form data structures (e.g., for form reset, backend error matching). | | **@vuepic/vue-datepicker** | Integrated internally for rendering modern and flexible date/time pickers. | --- ### πŸ”Ή Supported Field Types | Field Type | Description | |:---|:---| | `textField` | Standard single-line input (text, email, number, etc.) | | `textArea` | Multi-line textarea input | | `selectField` | Single-select dropdown menu | | `radioField` | Radio button group | | `multiSelect` | Multi-select dropdown (with tag view and custom styling) | | `passwordTextField` | Password input with hidden characters | | `datePickerField` | Modern date/time picker (date, month, week, year modes) | βœ… Each field is built as an independent Vue component internally β€” following clean modular structure. --- ### πŸ”Ή Internal Flow The internal flow of the Dynamic Form system is simple yet powerful: 1. **You define a form schema** using `CustomizableTextField` and `FieldType`. 2. **You bind the schema** to the `<DynamicForm>` component with `v-model` for form data. 3. **DynamicForm.vue dynamically renders** all fields based on your schema β€” applying global and per-field styles. 4. **Vuelidate is wired automatically** β€” every field's validation is live with no manual setup. 5. **Submissions** can be automatic (built-in button) or manual (external button triggering validation and submit). 6. **Backend validation errors** can be injected anytime using `setErrors()`, and fields display mapped errors immediately. 7. **Styling is fully customizable** globally (schema-wide) or per-field β€” supporting your own utility classes (Tailwind, Bootstrap, etc.) --- ### 🎯 Key Architectural Principles - **Schema First** β†’ You control everything through configuration, not through heavy templates. - **Modular Fields** β†’ Every field type is a clean, isolated component (`TextField`, `SelectField`, `DatePickerField`, etc.) - **Validation as Data** β†’ All field validations are attached declaratively through `ValidationSetup`. - **Zero Lock-In** β†’ No opinionated UI framework β€” you are free to style and extend freely. - **Error Handling Built-In** β†’ Live frontend validation + backend error injection supported out of the box. --- βœ… **Result:** You get a real-world form builder that feels **native, flexible, and fully under your control** β€” while staying lightweight, fast, and clean. <!-- Divider after Internal Structure Overview --> --- ## πŸ› οΈ Field Types Overview Vue Dynamic Form Builder supports a range of field types, covering most common real-world form needs. Each field type can be customized individually for label, placeholder, validation, styling, and behavior. | Field Type | Description | |:---|:---| | `textField` | Standard single-line input (text, email, number, tel, url, etc.) | | `textArea` | Multi-line text input for longer content (comments, descriptions, etc.) | | `selectField` | Single-select dropdown list | | `radioField` | Radio button group for choosing one option from multiple | | `multiSelect` | Multi-select dropdown with tag-style selections | | `passwordTextField` | Password input field with hidden characters | | `datePickerField` | Modern date/time picker supporting date, time, month, week, and year modes | βœ… All field types are internally modular β€” meaning you can easily extend, customize, or override their behavior as needed. βœ… Field-specific styling and validation rules are applied cleanly at the schema level. βœ… The system is designed to be flexible β€” you can mix multiple field types in a single form freely. <!-- Divider after Field Types Overview --> --- ## ✨ Features - **Schema-Driven:** Define all fields and layouts with a simple JavaScript schema. - **Highly Flexible Field Types:** Supports: - Standard Inputs (`text`, `email`, `number`, `password`, `tel`, `url`) - Text Area - Select Dropdown - Multi-Select Dropdown (with tag views and custom dropdown styles) - Radio Button Group - Date/Time Pickers (`date`, `dateTime`, `month`, `time`, `year`, `week`) - **Per-Field Design Overrides:** - Every field part (`div`, `input`, `label`, `error message`, `dropdown item`, etc.) can have custom CSS classes through the schema. - Global defaults (`textFieldStyle`) provided but fully overridable. - **Validation System:** - Includes built-in validations like: - Required - Email format - Minimum/Maximum Length - Minimum/Maximum Value - Value Range (Between) - URL format - Integer validation - Decimal (float) validation - Same-As (field matching) - Fully Custom Function Validators - **Backend Error Injection:** Accept and display backend validation errors automatically, mapping them to the correct fields. - **Manual or Auto Submission:** Choose between built-in submit button or fully manual form control (submit/reset from outside). - **Popup Modal Support:** Render fully functional forms inside modals without relying on external UI libraries. - **Developer Friendly:** Designed with real-world control, composability, and full extensibility β€” not a rigid black-box solution. - **No UI Framework Lock-in:** Seamlessly integrate with your own CSS, Tailwind, Bootstrap, or any design system of your choice. <!-- Divider after Features --> --- # πŸ“¦ Installation Guide ## 1. Install via NPM ```bash npm install @jubayer11/vue-dynamic-form-builder ``` ## 2. Install Required Peer Dependencies This package uses Vuelidate internally for validation. You must manually install the following dependencies: ```bash npm install vue@^3.5.13 @vuelidate/core@^2.0.3 @vuelidate/validators@^2.0.4 ``` | Package | Purpose | Recommended Version | |-----------------------|------------------------------------------------------|----------------------| | vue | Vue.js core framework (Vue 3.x required) | ^3.5.13 or latest | | @vuelidate/core | Validation engine (e.g., required, email) | ^2.0.3 | | @vuelidate/validators | Validator functions for your fields | ^2.0.4 | βœ… Vuelidate setup is already handled internally β€” no need to import or configure it manually. --- ## πŸ“¦ Included Internal Dependencies The following libraries are bundled inside the Dynamic Form Builder package: (You do not need to install these separately.) | Library | Purpose | |:---|:---| | moment | Flexible and reliable date/time formatting | | lodash (isEqual) | Internal deep object comparison for form data checking | | @vuepic/vue-datepicker | Lightweight and modern Date/Time picker UI for date-related fields | βœ… These dependencies are handled and maintained inside the package. βœ… No manual installation or imports needed. <!-- Divider after Internal Dependencies --> --- ## 3. Import Required CSS The package includes all styling bundled into a single compiled CSS file. Add this line in your project (typically in `main.js` or `main.ts`): ```js import '@jubayer11/vue-dynamic-form-builder/dist/style.css'; ``` βœ… This ensures all form fields, inputs, and components are styled as intended. βœ… Alternatively, you can also import it inside any local Vue component where the form is used: ```js import '@jubayer11/vue-dynamic-form-builder/dist/style.css'; ``` No SCSS setup is needed β€” everything is already compiled into CSS! Then, to run locally: ```bash npm run dev # Start local dev server (demo site) npm run build # Build for production ``` --- ## βœ… You're Ready! Now you're ready to use the Vue Dynamic Form Builder. Import the component and helper classes inside the local component where you plan to use the form: ```js import DynamicForm from '@jubayer11/vue-dynamic-form-builder' import { FieldType } from '@jubayer11/vue-dynamic-form-builder' import { fieldType } from '@jubayer11/vue-dynamic-form-builder' import { ValidationSetup } from '@jubayer11/vue-dynamic-form-builder' import { CustomizableTextField } from '@jubayer11/vue-dynamic-form-builder' ``` Drop `<DynamicForm />` into your Vue 3 component and bind it with a schema. --- ## πŸ”§ Optional: Local Development (Testing Source Code) If you want to test or contribute to the package locally: ```bash git clone https://github.com/jubayer11/vue-dynamic-form-builder.git cd vue-dynamic-form-builder npm install ``` --- ## ⚑ Quick Start Get started immediately with just a few lines of code! ```vue <template> <DynamicForm :schema="formSchema" v-model="formData" @submit="handleSubmit" /> </template> <script setup> import { ref, computed, reactive } from 'vue'; import { FieldType, CustomizableTextField } from '@jubayer/vue-dynamic-form-builder'; const nameField = new FieldType({ fieldType: 'textField', label: 'Name', forType: 'name', placeholder: 'Enter your name', }); const data = reactive(new CustomizableTextField()); data.addField(nameField); const formSchema = computed(() => data); const formData = ref(data.createInitialDataObject()); function handleSubmit() { console.log('Form submitted:', formData.value); } </script> ``` βœ… This shows: - Dynamic form generated by schema - Form data two-way bound via `v-model` - Manual submit action (`@submit` event) <!-- Divider after Quick Start --> --- ## πŸ› οΈ Schema Structure Every form is generated dynamically based on a **schema object**. The two core classes are: - **CustomizableTextField** β€” controls the overall form structure - **FieldType** β€” defines individual fields and their behaviors ```javascript import { FieldType, CustomizableTextField } from '@jubayer/vue-dynamic-form-builder'; const nameField = new FieldType({ fieldType: 'textField', label: 'Name', forType: 'name', }); const data = new CustomizableTextField(); data.addField(nameField); ``` βœ… You can add: - Validations (required, email, range, same-as, custom) - Default values - Field-specific custom styling - Flexible per-field behaviors βœ… The system is fully dynamic β€” you control fields, design, validations, and behavior via pure JavaScript. --- ## 🎨 Styling & Design Customization Use `updateStyle()` to control field design flexibly at different levels. ### πŸ§‘β€πŸ’Ό Style Hierarchy (How it works internally) - **Default Style** (`baseFieldClass`) β€” Global fallback from `textFieldStyle`. - **Custom Schema Style** (`customFieldClass`) β€” Layout-wide style changes (example: row layout, background colors, spacing). - **Per-Field Style** (`uniqueFieldClass`) β€” Specific to a single field (example: making only the "Username" field bold green). Final applied class order: ```html <input :class="[ baseFieldClass, customFieldClass, uniqueFieldClass, { 'textField__default__error': hasError }, baseIconPaddingClass, customIconPaddingClass, uniqueIconPaddingClass, ]" /> ``` --- ### ✨ How to Customize - **Schema Level (affect all fields together):** ```javascript import { CustomizableFieldsStyle } from 'vue-dynamic-form-builder'; const customStyle = new CustomizableFieldsStyle(); customStyle.update('field.mainDiv', 'dfutils__row'); customStyle.update('field.wrapper', 'dfutils__half'); data.updateStyle(customStyle); ``` - **Field Level (affect a specific field only):** ```javascript username.updateStyle('fieldAndError.field', 'dfutils__bg_lightblue dfutils__rounded_lg dfutils__py_lg'); username.updateStyle('label.label', 'text-bold text-green-600'); ``` βœ… You can override: - Input appearance - Label styling - Dropdown behavior - Multi-select tags - Error display - Submit button styling βœ… You can fully mix TailwindCSS, Bootstrap, or custom CSS classes easily. --- ## πŸ“œ Validation System The Dynamic Form Builder includes a powerful **schema-based validation system** powered by [Vuelidate](https://vuelidate-next.netlify.app/). Each field can define validations declaratively during schema setup β€” no manual form-wide watchers or rules. --- ### βœ… How to Add Validations Attach validations using either: ```javascript nameField.addValidations(ValidationSetup.required('Name is required.')); nameField.addValidations(ValidationSetup.minLength(2, 'Min 2 characters.')); ``` Or attach multiple validations at once: ```javascript passwordField.addValidationsArray([ ValidationSetup.required('Password required.'), ValidationSetup.minLength(6, 'Min 6 characters.') ]); ``` You can also skip message for auto-label fallback: ```javascript emailField.addValidations(ValidationSetup.email()); ``` --- ### πŸ” Custom Validations Use `ValidationSetup.custom()` to define full logic-based validations: ```javascript sportsField.addValidations( ValidationSetup.custom( (value) => Array.isArray(value) && value.length <= 3, 'You can select up to 3 sports only.' ) ); ``` Or field-to-field comparisons: ```javascript detailsField.addValidations( ValidationSetup.custom( (value, formData) => value !== formData.password, 'Details cannot match the password.' ) ); ``` βœ… Custom functions receive both `value` and the full `formData`. βœ… Must return `true` (valid) or `false` (invalid). --- ### 🧩 Supported Validation Methods | Method | Description | |:---|:---| | `required()` | Must not be empty | | `email()` | Must be valid email | | `minLength(n)` | Minimum string length | | `maxLength(n)` | Maximum string length | | `minValue(n)` | Minimum number | | `maxValue(n)` | Maximum number | | `between([min, max])` | Number must be between | | `sameAs(fieldName)` | Field must match another field | | `url()` | Must be a valid URL | | `integer()` | Must be a whole number | | `decimal()` | Must be a float | | `custom(fn)` | Fully custom validation logic | --- ### πŸ“‘ Backend Error Injection (Recommended) Whether using auto or manual submit β€” you can inject backend validation errors easily: ```javascript data.setErrors({ email: 'This email is already registered.', name: 'Username already taken.' }); ``` βœ… Keys must match `forType` defined during field creation. βœ… Display will automatically happen (highlighted error + message). --- ### 🧠 Real-world Backend Example: ```javascript const handleSubmit = async () => { try { startAnimation(); const response = await yourApiCall(formData.value); if (response.success) { alert('Form submitted successfully!'); } } catch (error) { if (error?.response?.data?.errors) { data.setErrors(error.response.data.errors); } else { console.error('Unexpected error:', error); } } finally { stopAnimation(); } }; ``` βœ… No need to manually track field-level errors β€” DynamicForm handles it internally. <!-- Divider after Validation System --> --- ## πŸ‘ Manual vs Automatic Submit By default, DynamicForm renders a built-in submit button inside the form. βœ… But you can disable it and manage submission **fully manually**. --- ### πŸ”Ή Automatic Submit (default) ```javascript const data = reactive(new CustomizableTextField()); data.updateSubmitButton(true, 'Submit'); ``` βœ… Clicking submit triggers validation and fires `@submit` event automatically. --- ### πŸ”Ή Manual Submit You can disable the built-in submit button: ```javascript const data = reactive(new CustomizableTextField()); data.updateSubmitButton(false); ``` And manage the form from the parent: ```vue <template> <DynamicForm :schema="formSchema" v-model="formData" ref="customForm" @submit="handleSubmit" /> <button @click="manualSubmit">Submit</button> <button @click="resetForm">Reset</button> </template> <script setup> const customForm = ref(null); function manualSubmit() { if (customForm.value && typeof customForm.value.handleSubmit === 'function') { customForm.value.handleSubmit(); } } function resetForm() { Object.assign(formData.value, data.createInitialDataObject()); } </script> ``` βœ… Full control over: - Button placement - Loading states - Conditional disables - Popup-confirm submissions --- ## ❓ FAQ ### 1. How do I reset the form to its initial state? You can reset the form by copying the initial data object back into your `formData`: ```javascript function resetForm() { Object.assign(formData.value, data.createInitialDataObject()); } ``` βœ… `formData` will be reset to the default values defined in your schema. --- ### 2. How do I manually trigger form submission? If you are using manual submit mode, you can trigger form submission like this: ```html <button class="action-btn submit-btn" @click="manualSubmit"> Submit </button> ``` ```javascript function manualSubmit() { if (customForm.value && typeof customForm.value.handleSubmit === "function") { customForm.value.handleSubmit(); // Validates and emits submit event } else { console.error("handleSubmit is not a function on CustomForm"); } } ``` βœ… This will trigger validation and call your custom `handleSubmit` method if validation passes. --- ### 3. How do I disable the built-in submit button and control buttons manually? By default, the built-in submit button is disabled. But to ensure manual control, call: ```javascript data.updateSubmitButton(false); // Disables built-in submit button ``` βœ… You can then manage Submit/Reset externally. --- ### 4. How can I inject backend/server-side validation errors into the form? Inside your submit method (usually in a `try/catch` block), you can inject backend errors like this: ```javascript data.setErrors({ email: "This email is already registered.", name: "Username already taken.", }); ``` βœ… Backend error keys must match field `forType`. βœ… DynamicForm automatically highlights the field and shows the message. --- ### 5. How do I apply custom styles to a specific field only? Use `updateStyle()`: ```javascript username.updateStyle("fieldAndError.field", "dfutils__bg_lightblue dfutils__rounded_lg dfutils__py_lg"); username.updateStyle("label.label", "dfutils__label_right dfutils__label_bold dfutils__label_green"); ``` βœ… Field-specific styling is very flexible. --- ### 6. Can I control the default value of a field? Yes! You can set `defaultValue` when creating a field: ```javascript const username = new FieldType({ fieldType: fieldType.textField, label: "Username", forType: "username", defaultValue: "jubayer", }); ``` βœ… Prefills initial values inside the form automatically. --- ### 7. Can I dynamically add or remove fields from the form after creation? Currently, **the package does not officially provide dynamic add/remove after creation**. βœ… You could manipulate the schema manually and rebuild, but the focus is on predefining a clean schema first. --- ### 8. Can I create a fully custom field type if needed? Yes! Since fields like `TextField.vue` and `DatePickerField.vue` are modular components: βœ… You can create your own field component. βœ… Extend DynamicForm easily. βœ… Handle validation, styling, and schema mapping yourself. --- ### 9. How do I validate a field using a custom validation function? Use `ValidationSetup.custom()`: ```javascript detailsField.addValidations( ValidationSetup.custom( (value, formData) => value !== formData.password, "Details cannot match the password." ) ); ``` βœ… You have full access to the current field value and the entire form. --- ### 10. Can I use the form inside a popup modal? How does validation and submission behave inside modals? Yes! DynamicForm works perfectly inside a popup/modal. Example: ```vue <DynamicForm :schema="formSchema" v-model="formData" ref="popupForm" @submit="handleSubmit" /> <button @click="manualSubmit">Submit</button> ``` βœ… Manual submission inside modals works exactly like outside forms. βœ… No third-party libraries needed β€” just your custom modal. <!-- Divider after FAQ --> --- ## πŸ§ͺ Demo Gallery Explore real-world examples of how you can use `@jubayer/vue-dynamic-form-builder` to build powerful and flexible forms. Each example is available inside the `demo/` folder. | Demo | Highlights | |:---|:---| | **Basic Prefilled Form** | Prefilled data, required fields, email validation, backend error simulation | | **Row/Column Layout Form** | Responsive row layout, half-width fields, structured grouping | | **Manual Submit + Custom Buttons** | External submit/reset buttons, full manual control | | **Custom Styling per Field** | Per-field label, input, and error styling overrides | | **Popup Form in Modal** | Full form handling inside a modal | | **All Date/Time Picker Modes** | Supports date, time, month, week, and year picking | πŸ”— **Live Demo**: [https://jubayer11.github.io/vue-dynamic-form-builder/](https://jubayer11.github.io/vue-dynamic-form-builder/) ### πŸ“‚ Where to Find Demo Files | Demo | File Location | |:---|:---| | **Basic Prefilled Form** | `src/demo/components/demo/DemoPrefilledForm.vue` | | **Row/Column Layout Form** | `src/demo/components/demo/DemoRowForm.vue` | | **Manual Submit + Custom Buttons** | `src/demo/components/demo/DemoManualSubmitForm.vue` | | **Custom Styling per Field** | `src/demo/components/demo/DemoCustomStyleForm.vue` | | **Popup Form in Modal** | `src/demo/components/demo/DemoPopupForm.vue` | | **All Date/Time Picker Modes** | `src/demo/components/demo/DemoDateForm.vue` | βœ… Demos are real-world, production-grade examples. <!-- Divider after Demo Gallery --> --- ## πŸ“œ License [MIT License](./LICENSE) Β© 2025 Jubayer Ahmed <!-- Divider after License --> --- ## πŸ™Œ Credits Designed and developed with ❀️ by **Jubayer Ahmed** ([Portfolio](https://www.jubayerahmed.com/)) β€” Dynamic Systems β€’ Clean Code β€’ Developer Empowerment <!-- Divider after Credits --> --- ## 🎯 Final Touches - Full Vue 3 + Composition API ready - 100% lightweight and modular - No rigid styles β€” you control everything - Inspired by real-world problems, built for serious developers <!-- Divider after Final Touches --> --- --- ## πŸ”— Related Projects Looking for a customizable, fully responsive table to pair with your Vue app? πŸ‘‰ Check out [`@jubayer11/vue-dynamic-table-builder`](https://www.npmjs.com/package/@jubayer11/vue-dynamic-table-builder) A powerful Vue 3 table builder with pagination, action buttons, responsive columns, expandable rows, and deep style/config customization. --- ✨ End of README ✨ If you enjoy this package, consider starring ⭐ the repository β€” it helps more developers discover it! 🀝 Interested in contributing? Feel free to open issues, suggest improvements, or submit pull requests β€” collaboration is always welcome!