DynamicForm
Dynamic form component for quickly building form interfaces based on configuration.
TIP
In addition to the full dynamic form component, we also provide a standalone EzFormItem component that can be used to build custom form layouts.
Overview
DynamicForm is designed for building forms in a configuration-driven way. Compared with writing a large number of el-form-item blocks manually, it is better suited for business forms with many fields, relatively regular structure, and frequent iteration.
It mainly helps with these scenarios:
- Use
itemsas a single-group shorthand for lightweight form scenarios. - Use
groupsas the full configuration model for sectioned forms with titles, descriptions, group-level layout, and group-level slots. - Reuse built-in field types, required rules, visibility linkage, and disabled linkage to reduce repetitive boilerplate.
- Keep both field-level and group-level slots, so you can move between standardized configuration and high customization when needed.
Recommended usage:
- Use
groupsas the standard long-term configuration mode. - Use
itemsonly as a shorthand for simple single-section forms or lightweight query areas. - If one area becomes too custom for configuration-driven rendering, combine
EzFormItemor group slots for that part.
Basic Usage
Component Types
Form Validation
Custom Slots
Grouped Form
Field Serialization
Attributes
| Attribute | Description | Type | Required | Default |
|---|---|---|---|---|
| v-model | Two-way bound form data | Record | No | {} |
| items | Shorthand config for a single-group form | FormItemConfig[] | No | [] |
| groups | Standard grouped configuration (recommended) | FormGroupConfig[] | No | [] |
| cols | Grid layout columns | number | No | 1 |
| gutter | Grid spacing | number | No | 20 |
| Other Form Props | Passed through to el-form | Partial | No | - |
FormItemConfig
| Attribute | Description | Type | Required | Default |
|---|---|---|---|---|
| prop | Field name | string | Yes | - |
| label | Label | string | No | - |
| type | Component type. Built-in branches only accept FormItemType literals; custom rendering should use component | FormItemType | No | - |
| defaultValue | Default value | any | No | - |
| rules | Validation rules | FormItemRule | No | - |
| required | Required | boolean | No | false |
| requiredMessage | Required message | string | No | - |
| span | Occupied grid columns | number | No | - |
| hidden | Hidden | boolean | No | false |
| disabled | Disabled | boolean | No | false |
| placeholder | Placeholder | string | No | - |
| options | Option configuration. Select supports grouped options, radio/checkbox use their wrapped option types, and tree-select/cascader pass structured data sources through | FormItemOption[] | No | - |
| attrs | Component attributes passed to the rendered control. select/radio/checkbox/upload-images, tree-select, and cascader expose more specific public prop subsets; other built-in controls are still loosely forwarded | Record | No | - |
| component | Custom field component. It should follow the modelValue / update:modelValue / disabled field contract | Component | No | - |
| itemAttrs | Additional el-form-item attributes | Partial<FormItemProps> | No | - |
| show | Linkage display condition | Function | No | - |
| disabledWhen | Linkage disable condition | Function | No | - |
| serialize | Field serializer before submit | Function | No | - |
| deserialize | Field deserializer when restoring external data | Function | No | - |
FormGroupConfig
| Attribute | Description | Type | Required | Default |
|---|---|---|---|---|
| name | Unique group key | string | No | - |
| title | Group title | string | No | - |
| description | Group description | string | No | - |
| items | Items in this group | FormItemConfig[] | Yes | [] |
| cols | Grid columns inside this group | number | No | Inherit global cols |
| gutter | Grid spacing inside this group | number | No | Inherit global gutter |
| hidden | Hide this group | boolean | No | false |
| show | Group visibility condition | Function | No | - |
| className | Group container class | string | No | - |
| style | Group container style | string | Record | No | - |
| headerClassName | Group header class | string | No | - |
| headerStyle | Group header style | string | Record | No | - |
| bodyClassName | Group body class | string | No | - |
| bodyStyle | Group body style | string | Record | No | - |
| headerSlot | Custom group header slot name | string | No | group-header-${name} |
| slot | Custom group content slot name | string | No | group-${name} |
Data Initialization and v-model
- v-model: Use standard Vue 3 two-way binding. Field changes are synced back to the parent model.
- defaultValue: A config default is only applied when the corresponding field does not exist in the bound model.
- items / groups are exclusive:
itemsandgroupscannot be provided at the same time. The component throws immediately when both are present. - Mode positioning:
groupsis the full configuration model.itemsis only a shorthand for a single-group form and will not gain group-level capabilities. - Type narrowing:
FormItemConfignow narrowsattrs/optionsforselect,radio,checkbox,tree-select,cascader,upload-images, andcomponentbranches instead of treating every field shape as the same loose object.tree-selectandcascadernow also use stable attrs subsets. - Custom component contract: the
componentbranch is no longer treated as an arbitrary component slot; it is expected to behave like a field component.
Data Flow Design
This component supports standard Vue 3 v-model two-way binding:
- Use
v-modelas the source of truth for business state. - Use
getFormData()to retrieve a deep-cloned snapshot of the current form state. - Use
getSubmitData()to retrieve the submit payload after field-levelserializeis applied. - Use
setFormData()to merge or replace form values explicitly. - Use
setSubmitData()to restore submit payload data back into the UI model withdeserialize. Extra payload fields that are not declared as formprops will not be written intov-model. - Use
captureInitialData()to store the current state as the new reset baseline. - Use
resetForm()to restore the form back to the current baseline.
Notes
- The component automatically fills missing
propkeys declared initemsorgroups, so Element Plus validation can track those fields reliably. - Replacing the bound
v-modelobject from outside is supported; the component will normalize the structure again after replacement. setFormData()clears current validation state after updating the data.getSubmitData()does not mutate the currentv-model; it only returns a transformed copy.setSubmitData()only writes back declared form fields, so request-only fields such as split date keys can stay outside the UI model.- After the initial mount finishes, the component stores an initial snapshot automatically.
resetForm()restores that snapshot by default.
FormItemType
| Name | Description |
|---|---|
| INPUT | Input |
| TEXTAREA | Textarea |
| NUMBER | Number Input |
| PASSWORD | Password Input |
| SELECT | Select (wrapped component) |
| RADIO | Radio (wrapped component) |
| CHECKBOX | Checkbox (wrapped component) |
| DATE | Date Picker |
| DATETIME | DateTime Picker |
| DATERANGE | Date Range |
| DATETIMERANGE | DateTime Range |
| TIME | Time Picker |
| TIMERANGE | Time Range |
| UPLOAD_IMAGES | Image Upload (wrapped component) |
| SWITCH | Switch |
| TREE_SELECT | Tree Select |
| CASCADER | Cascader |
| SLIDER | Slider |
| RATE | Rate |
Methods
| Method | Description | Type |
|---|---|---|
| validate | Validate form | Function |
| validateField | Validate specified fields | Function |
| clearValidate | Clear validation | Function |
| getFormData | Get form data (call on demand) | Function |
| getSubmitData | Get serialized submit payload | Function |
| setFormData | Set form data (auto clear validation, support merge or replace) | Function |
| setSubmitData | Set submit payload and deserialize it into the UI model | Function |
| resetForm | Reset the form to the current baseline | Function |
| captureInitialData | Store the current form state as the new baseline | Function |
Slots
| Name | Description | Parameters |
|---|---|---|
[prop] | Custom form item content | { item: FormItemConfig, value: any, formData: Record } |
label-[prop] | Custom form item label | { item: FormItemConfig } |
group-header | Shared group header slot | { group: FormGroupConfig, index: number, items: FormItemConfig[], formData: Record } |
group | Shared group content slot | { group: FormGroupConfig, index: number, items: FormItemConfig[], formData: Record } |
group-header-[name] | Named group header slot | { group: FormGroupConfig, index: number, items: FormItemConfig[], formData: Record } |
group-[name] | Named group content slot | { group: FormGroupConfig, index: number, items: FormItemConfig[], formData: Record } |