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.
-
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.
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.
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. |
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. |
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.
The internal flow of the Dynamic Form system is simple yet powerful:
-
You define a form schema using
CustomizableTextField
andFieldType
. -
You bind the schema to the
<DynamicForm>
component withv-model
for form data. - DynamicForm.vue dynamically renders all fields based on your schema — applying global and per-field styles.
- Vuelidate is wired automatically — every field's validation is live with no manual setup.
- Submissions can be automatic (built-in button) or manual (external button triggering validation and submit).
-
Backend validation errors can be injected anytime using
setErrors()
, and fields display mapped errors immediately. - Styling is fully customizable globally (schema-wide) or per-field — supporting your own utility classes (Tailwind, Bootstrap, etc.)
- 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.
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.
-
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
)
- Standard Inputs (
-
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.
- Every field part (
-
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
- Includes built-in validations like:
-
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.
npm install @jubayer11/vue-dynamic-form-builder
This package uses Vuelidate internally for validation.
You must manually install the following dependencies:
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.
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.
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
):
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:
import '@jubayer11/vue-dynamic-form-builder/dist/style.css';
No SCSS setup is needed — everything is already compiled into CSS!
Then, to run locally:
npm run dev # Start local dev server (demo site)
npm run build # Build for production
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:
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.
If you want to test or contribute to the package locally:
git clone https://github.com/jubayer11/vue-dynamic-form-builder.git
cd vue-dynamic-form-builder
npm install
Get started immediately with just a few lines of code!
<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)
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
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.
Use updateStyle()
to control field design flexibly at different levels.
-
Default Style (
baseFieldClass
) — Global fallback fromtextFieldStyle
. -
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:
<input
:class="[
baseFieldClass,
customFieldClass,
uniqueFieldClass,
{ 'textField__default__error': hasError },
baseIconPaddingClass,
customIconPaddingClass,
uniqueIconPaddingClass,
]"
/>
-
Schema Level (affect all fields together):
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):
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.
The Dynamic Form Builder includes a powerful schema-based validation system powered by Vuelidate.
Each field can define validations declaratively during schema setup — no manual form-wide watchers or rules.
Attach validations using either:
nameField.addValidations(ValidationSetup.required('Name is required.'));
nameField.addValidations(ValidationSetup.minLength(2, 'Min 2 characters.'));
Or attach multiple validations at once:
passwordField.addValidationsArray([
ValidationSetup.required('Password required.'),
ValidationSetup.minLength(6, 'Min 6 characters.')
]);
You can also skip message for auto-label fallback:
emailField.addValidations(ValidationSetup.email());
Use ValidationSetup.custom()
to define full logic-based validations:
sportsField.addValidations(
ValidationSetup.custom(
(value) => Array.isArray(value) && value.length <= 3,
'You can select up to 3 sports only.'
)
);
Or field-to-field comparisons:
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).
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 |
Whether using auto or manual submit — you can inject backend validation errors easily:
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).
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.
By default, DynamicForm renders a built-in submit button inside the form.
✅ But you can disable it and manage submission fully manually.
const data = reactive(new CustomizableTextField());
data.updateSubmitButton(true, 'Submit');
✅ Clicking submit triggers validation and fires @submit
event automatically.
You can disable the built-in submit button:
const data = reactive(new CustomizableTextField());
data.updateSubmitButton(false);
And manage the form from the parent:
<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
You can reset the form by copying the initial data object back into your formData
:
function resetForm() {
Object.assign(formData.value, data.createInitialDataObject());
}
✅ formData
will be reset to the default values defined in your schema.
If you are using manual submit mode, you can trigger form submission like this:
<button class="action-btn submit-btn" @click="manualSubmit">
Submit
</button>
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.
By default, the built-in submit button is disabled.
But to ensure manual control, call:
data.updateSubmitButton(false); // Disables built-in submit button
✅ You can then manage Submit/Reset externally.
Inside your submit method (usually in a try/catch
block), you can inject backend errors like this:
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.
Use updateStyle()
:
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.
Yes!
You can set defaultValue
when creating a field:
const username = new FieldType({
fieldType: fieldType.textField,
label: "Username",
forType: "username",
defaultValue: "jubayer",
});
✅ Prefills initial values inside the form automatically.
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.
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.
Use ValidationSetup.custom()
:
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:
<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.
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/
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.
MIT License © 2025 Jubayer Ahmed
Designed and developed with ❤️ by Jubayer Ahmed (Portfolio) — Dynamic Systems • Clean Code • Developer Empowerment
- 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
Looking for a customizable, fully responsive table to pair with your Vue app?
👉 Check out @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!