You own the UI
Define your field types once in your own template — the HTML, the components, the styling. The library handles the rest.
An opinionated extension on top of vee-validate — it handles the structure, you have full control over the HTML.
Vue Dynamic Form is an opinionated layer built on top of vee-validate — you keep all its validation power, and gain a structured engine for the problems most forms eventually run into.
It separates two things that usually get tangled together: what your form looks like and how it behaves.
You describe your form as metadata — a plain object tree that says which fields exist, whether they repeat, whether they're part of a group or a choice, and what validation rules apply. The library reads that description and takes care of the rest: generating field paths, managing repeating sections, tracking which choice branch is active, and keeping everything in sync with vee-validate.
Your template layer stays completely under your control. You decide which field types your app supports, what extra properties they need, and what HTML gets rendered.
The metadata model is inspired by XSD — one of the most battle-tested formats for describing structured data. That heritage means the model can express almost any form scenario you'll encounter: required fields, length limits, allowed values, repeating groups, conditional branches, and nested structures. You don't need to know anything about XSD to use it. The benefit is that the hard edge cases were already thought through and tested.
A concrete demo for a SaaS team collecting everything needed to onboard a new client. It highlights reusable templates, grouped fields, repeatable contacts, mutually exclusive launch paths, and computed fields that become required only when they matter.
IsDirty: true
Touched: false
Valid: true
// form values:
{
"company": {},
"projectContacts": [
{}
],
"launchApproach": {
"selfServe": {
"field-0": true
},
"guidedRollout": {}
}
}
Most form logic comes down to "if this field has a certain value, show/hide/require/change that other field." In practice that means conditional logic spread across your form component — fields hidden with v-if, others disabled through computed properties, options reloaded in watch() calls. All in the same component, but scattered through it. As forms grow, tracing what controls each field becomes its own challenge.
Vue Dynamic Form keeps all of that with the field itself. Each field carries a computedProps function right next to its name, type, and validation rules — so the full picture of a field stays in one place:
const fields: Metadata[] = [
{ name: 'accountType', type: 'select', ... },
{
name: 'vatNumber',
type: 'text',
fieldOptions: { label: 'VAT Number' },
computedProps: [
(field) => { field.disabled = accountType.value !== 'business' }
]
}
]The function reads whatever it needs; Vue detects those reads and re-runs it automatically when they change. No watch() calls, no v-if conditions scattered through the template — you write the logic, not the subscription.
Your components provide the functionality — a field that can be disabled, a select with configurable options, an input that can be hidden. The form definition decides when to use it. Components stay clean and reusable; the form definition is the single source of truth for behaviour.
README.md at the repository root for GitHub-friendly orientationpackages/core/README.md for the detailed package explanation