Form
Form encapsulation, generates forms through configuration.
TIP
If form item components support placeholder, clearable, filterable, these attributes are configured by default
Basic Usage
- Pass
columnsto define the form,modelValuefor form data,optionsfor data option sources,componentfor form item component,fieldfor field name,fieldPropsfor component attribute configuration,formItemPropsfor form item decorator component attribute configuration FormItemcomponent attributes (form item decorator component) are configured in theformItemPropsfield. For convenience, some fields can also take effect when configured directly in thecolumnitem (e.g.:label,required,message,rule, etc.)- Events use
on+event name
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import { ElInput } from 'element-plus'
const formRef = ref()
const formData = ref({
name: '',
gender: '',
time: [],
})
const options = {
gender: [
{ label: 'Male', value: '1' },
{ label: 'Female', value: '2' },
],
}
const columns = [
{
component: ElInput,
field: 'name',
label: 'Name',
onInput: (val: string) => {
console.log(val, 'input event')
},
onChange: (val: string) => {
console.log(val, 'change event')
},
required: true,
},
{
component: 'select',
field: 'gender',
label: 'Gender',
onChange: (val: string) => {
console.log(val, 'change event')
},
onFocus: () => {
console.log('focus event')
},
},
{
component: 'el-date-picker',
field: 'time',
label: 'Date',
fieldProps: {
type: 'daterange',
startPlaceholder: 'Start date',
endPlaceholder: 'End date',
},
onChange: (val: string[]) => {
console.log(val, 'change event')
},
},
{
slot: 'button',
},
]
function reset() {
formRef.value.resetFields()
}
function submit() {
formRef.value.validate((valid: boolean) => {
if (valid)
console.log(formData.value, 'config.formData')
else
console.log('error')
})
}
</script>
<template>
<z-form
ref="formRef"
v-model="formData"
:options="options"
:columns="columns"
label-width="80px"
size="small"
>
<template #button>
<div class="w-full flex">
<el-button class="w-full" @click="reset">
Reset
</el-button>
<el-button type="primary" class="w-full" @click="submit">
Submit
</el-button>
</div>
</template>
</z-form>
</template>Column Layout
Pass column to the form to support 1 ~ 3 column layout, default is 1 column layout.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const formRef = ref()
const formData = ref({
name: '',
gender: '',
age: '',
})
const options = {
gender: [
{ label: 'Male', value: '1' },
{ label: 'Female', value: '2' },
],
}
const columns = [
{
component: 'input',
field: 'name',
label: 'Name',
required: true,
},
{
component: 'select',
field: 'gender',
label: 'Gender',
},
{
component: 'input',
label: 'Age',
field: 'age',
},
{
slot: 'button',
},
]
function submit() {
formRef.value.validate((valid: boolean) => {
if (valid) {
ElMessage.success('success')
console.log(formData.value, 'formData.value')
}
else {
console.log('error')
}
})
}
</script>
<template>
<z-form
ref="formRef"
v-model="formData"
:options="options"
:columns="columns"
label-width="90px"
size="small"
:column="2"
>
<template #button>
<el-button class="w-full" type="primary" @click="submit">
Submit
</el-button>
</template>
</z-form>
</template>Custom Layout
If the column layout does not meet the requirements, you can configure span, offset, pull, push, xs, sm, md, lg, xl in the column item to achieve a custom responsive layout
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const formRef = ref()
const formData = ref({
name: '',
gender: '',
age: '',
})
const options = {
gender: [
{ label: 'Male', value: '1' },
{ label: 'Female', value: '2' },
],
}
const columns = [
{
component: 'input',
field: 'name',
label: 'Name',
required: true,
span: 24,
},
{
component: 'select',
field: 'gender',
label: 'Gender',
span: 12,
},
{
component: 'input',
label: 'Age',
field: 'age',
span: 12,
},
{
span: 24,
slot: 'button',
},
]
function submit() {
formRef.value.validate((valid: boolean) => {
if (valid) {
ElMessage.success('success')
console.log(formData.value, 'formData.value')
}
else {
console.log('error')
}
})
}
</script>
<template>
<z-form
ref="formRef"
v-model="formData"
:options="options"
:columns="columns"
label-width="90px"
size="small"
>
<template #button>
<el-button class="w-full" type="primary" @click="submit">
Submit
</el-button>
</template>
</z-form>
</template>Tooltip
Pass tooltip, extra, and colon in column to configure tooltip, extra info, and colon. tooltip and extra support string and render function. The form can pass colon to uniformly configure colons for all form items.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { h, ref } from 'vue'
import { ElMessage } from 'element-plus'
const formRef = ref()
const formData = ref({
name: '',
gender: '',
age: '',
})
const options = {
gender: [
{ label: 'Male', value: '1' },
{ label: 'Female', value: '2' },
],
}
const columns = [
{
component: 'input',
field: 'name',
label: 'Name',
tooltip: 'Name tooltip',
extra: 'extraSlot',
required: true,
},
{
component: 'select',
field: 'gender',
label: 'Gender',
colon: false,
tooltip: () => h('span', {}, 'Gender hint'),
required: true,
},
{
component: 'input',
label: 'Age',
field: 'age',
formItemProps: {
tooltip: 'Age tooltip',
extra: () => h('span', {}, 'This is extra info'),
colon: false,
},
},
{
slot: 'button',
},
]
function submit() {
formRef.value.validate((valid: boolean) => {
if (valid) {
ElMessage.success('success')
console.log(formData.value, 'formData.value')
}
else {
console.log('error')
}
})
}
</script>
<template>
<z-form
ref="formRef"
v-model="formData"
:options="options"
:columns="columns"
label-width="90px"
size="small"
:column="2"
colon
>
<template #extraSlot>
<span>Hint hint hint hint hint hint hint hint hint hint hint hint hint hint hint hint hint hint hint</span>
</template>
<template #button>
<el-button class="w-full" type="primary" @click="submit">
Submit
</el-button>
</template>
</z-form>
</template>tooltip supports passing a render function and slot customization.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { h, ref } from 'vue'
import { ElMessage } from 'element-plus'
const formRef = ref()
const formData = ref({
name: '',
gender: '',
age: '',
})
const options = {
gender: [
{ label: 'Male', value: '1' },
{ label: 'Female', value: '2' },
],
}
const columns = [
{
component: 'input',
field: 'name',
label: 'Name',
tooltip: {
reference: () => h('span', {}, '?'),
content: 'Name hint',
},
extra: 'extraSlot',
required: true,
},
{
component: 'select',
field: 'gender',
label: 'Gender',
colon: false,
tooltip: () => h('span', {}, 'Gender hint'),
required: true,
},
{
component: 'input',
label: 'Age',
field: 'age',
formItemProps: {
tooltip: {
reference: 'tooltipSlot',
content: () => h('span', {}, 'Custom age hint'),
},
colon: false,
},
},
{
slot: 'button',
},
]
function submit() {
formRef.value.validate((valid: boolean) => {
if (valid) {
ElMessage.success('success')
console.log(formData.value, 'formData.value')
}
else {
console.log('error')
}
})
}
</script>
<template>
<z-form
ref="formRef"
v-model="formData"
:options="options"
:columns="columns"
label-width="90px"
size="small"
:column="2"
colon
>
<template #tooltipSlot>
<el-icon class="cursor-pointer">
<i-delete />
</el-icon>
</template>
<template #button>
<el-button class="w-full" type="primary" @click="submit">
Submit
</el-button>
</template>
</z-form>
</template>Validation
- Add
requiredincolumnsform items, or setrequiredinformItemPropsto make it required. The validation message will be automatically generated based onlabelor can be customized. - Pass
rulesinformto define form validation rules. - Configure
rulesincolumnsform items to define the validation rules for the current form item.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const formRef = ref()
const formData = ref({
name: '',
gender: '',
age: '',
hobby: '',
})
const options = {
gender: [
{ label: 'Male', value: '1' },
{ label: 'Female', value: '2' },
],
}
const rules = {
age: [{ required: true, message: 'Age is required' }],
}
const columns = [
{
component: 'input',
field: 'name',
label: 'Name',
required: true,
},
{
component: 'select',
field: 'gender',
formItemProps: {
required: true,
label: 'Gender',
},
},
{
component: 'input',
label: 'Age',
field: 'age',
},
{
component: 'input',
label: 'Hobby',
field: 'hobby',
rules: {
required: true,
message: 'Please enter a hobby',
},
},
{
slot: 'button',
},
]
function submit() {
formRef.value.validate((valid: boolean) => {
if (valid) {
ElMessage.success('success')
console.log(formData.value, 'formData.value')
}
else {
console.log('error')
}
})
}
</script>
<template>
<z-form
ref="formRef"
v-model="formData"
:options="options"
:columns="columns"
label-width="90px"
size="small"
:rules="rules"
:column="3"
>
<template #button>
<el-button class="w-full" type="primary" @click="submit">
Submit
</el-button>
</template>
</z-form>
</template>Linkage
Pass hide (supports boolean or function type) to column form items to configure linkage hide/show for form items.
Some business scenarios require using v-show to determine component visibility. Pass the show field (supports boolean or function type) to column form items.
If the name input has a value, the gender select box will show. Then try selecting gender; the age form item will appear.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const formRef = ref()
const formData = ref({
name: '',
gender: '',
age: '',
})
const options = {
gender: [
{ label: 'Male', value: '1' },
{ label: 'Female', value: '2' },
],
}
const columns = [
{
component: 'input',
field: 'name',
label: 'Name',
required: true,
},
{
component: 'select',
field: 'gender',
label: 'Gender',
show: (formData: any) => formData.name,
},
{
component: 'input',
label: 'Age',
hide: formData => formData.gender === '1' || !formData.gender,
field: 'age',
},
{
slot: 'button',
},
]
function submit() {
formRef.value.validate((valid: boolean) => {
if (valid) {
ElMessage.success('success')
console.log(formData.value, 'formData.value')
}
else {
console.log('error')
}
})
}
</script>
<template>
<z-form
ref="formRef"
v-model="formData"
:options="options"
:columns="columns"
label-width="90px"
size="small"
:column="2"
>
<template #button>
<el-button class="w-full" type="primary" @click="submit">
Submit
</el-button>
</template>
</z-form>
</template>Custom Form Items
We can use slot or render to customize form item content. Please still pass the field field; otherwise, reset cannot clear the data (field not passed will default to slot).
<script lang="ts" setup>
import { h, ref } from 'vue'
const formRef = ref()
const formData = ref({
name: '',
gender: '',
age: '',
})
const options = {
gender: [
{ label: 'Male', value: '1' },
{ label: 'Female', value: '2' },
],
}
const columns = [
{
component: 'input',
field: 'name',
label: 'Name',
required: true,
},
{
slot: 'gender',
field: 'gender',
label: 'Gender',
},
{
label: 'Age',
render: () => h('span', {}, 'Age details'),
},
]
</script>
<template>
<z-form
ref="formRef"
v-model="formData"
:columns="columns"
label-width="90px"
size="small"
>
<template #gender>
<z-select v-model="formData.gender" :options="options.gender" clearable filterable placeholder="Please select a gender" />
</template>
</z-form>
</template>Custom label and error
label and error support strings, render functions, or concatenated Slot strings.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { h, ref } from 'vue'
import { ElMessage } from 'element-plus'
const formRef = ref()
const formData = ref({
name: '',
gender: '',
age: '',
})
const options = {
gender: [
{ label: 'Male', value: '1' },
{ label: 'Female', value: '2' },
],
}
const columns = [
{
component: 'input',
field: 'name',
label: () => h('span', {}, 'Name'),
error: 'error message',
required: true,
},
{
component: 'select',
field: 'gender',
label: 'labelSlot',
required: true,
error: h('span', {}, 'errorSlot'),
},
{
component: 'input',
field: 'age',
label: 'Age',
required: true,
error: 'errorSlot',
},
{
slot: 'button',
},
]
function submit() {
formRef.value.validate((valid: boolean) => {
if (valid) {
ElMessage.success('success')
console.log(formData.value, 'formData.value')
}
else {
console.log('error')
}
})
}
</script>
<template>
<z-form
ref="formRef"
v-model="formData"
:columns="columns"
:options="options"
label-width="90px"
size="small"
>
<template #labelSlot>
<span>Gender</span>
</template>
<template #errorSlot>
<span>Age is required</span>
</template>
<template #button>
<el-button class="w-full" type="primary" @click="submit">
Submit
</el-button>
</template>
</z-form>
</template>Form Item Order
Pass order to form items to support custom order. If not passed, it defaults to placing at the end in order.
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import { ElInput } from 'element-plus'
const formRef = ref()
const formData = ref({
name: '',
gender: '',
time: [],
})
const options = {
gender: [
{ label: 'Male', value: '1' },
{ label: 'Female', value: '2' },
],
}
const columns = [
{
component: 'el-input',
field: 'name',
label: 'Address',
},
{
component: ElInput,
field: 'name',
label: 'Name',
order: 2,
},
{
component: 'select',
field: 'gender',
label: 'Gender',
order: 3,
},
{
component: 'el-date-picker',
field: 'time',
label: 'Date',
order: 1,
},
{
slot: 'button',
},
]
function reset() {
formRef.value.resetFields()
}
function submit() {
formRef.value.validate((valid: boolean) => {
if (valid)
console.log(formData.value, 'config.formData')
else
console.log('error')
})
}
</script>
<template>
<z-form
ref="formRef"
v-model="formData"
:options="options"
:columns="columns"
label-width="80px"
size="small"
>
<template #button>
<div class="w-full flex">
<el-button class="w-full" @click="reset">
Reset
</el-button>
<el-button type="primary" class="w-full" @click="submit">
Submit
</el-button>
</div>
</template>
</z-form>
</template>Combine with Table
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
interface RowData {
name: string
address: string
}
const formRef = ref()
const formData = ref({
name: '',
gender: '',
time: [],
tableData: [{ name: 'steven', address: '' }],
})
const options = {
gender: [
{ label: 'Male', value: '1' },
{ label: 'Female', value: '2' },
],
}
const columns = computed(() => [
{
component: 'el-input',
field: 'name',
label: 'Name',
onInput: (val: string) => {
console.log(val, 'input event')
},
onChange: (val: string) => {
console.log(val, 'change event')
},
required: true,
},
{
'component': 'z-table',
'field': 'tableData',
'label': 'Table',
'onUpdate:data': (data: RowData[]) => {
console.log(data, 'data')
formData.value.tableData = data
},
'fieldProps': {
data: formData.value.tableData,
toolBar: false,
columns: [
{
label: 'Name',
prop: 'name',
},
{
component: 'el-input',
label: 'Address',
prop: 'address',
},
],
},
},
{
slot: 'button',
},
])
function reset() {
formRef.value.resetFields()
}
function submit() {
formRef.value.validate((valid: boolean) => {
if (valid)
console.log(formData.value, 'config.formData')
else
console.log('error')
})
}
</script>
<template>
<z-form
ref="formRef"
v-model="formData"
:options="options"
:columns="columns"
label-width="80px"
size="small"
>
<template #button>
<div class="w-full flex">
<el-button class="w-full" @click="reset">
Reset
</el-button>
<el-button type="primary" class="w-full" @click="submit">
Submit
</el-button>
</div>
</template>
</z-form>
</template>z-form Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| modelValue | Form data object | object | — |
| type | Form type | normal / group / collapse / array / step | normal |
| rules | Form validation rules | object | — |
| columns | Form items | array | — |
| options | Data source of form options | object | — |
| column | Number of form columns (convenient layout) | number | 1 |
| colon | Colon of form item | boolean | false |
| max | Maximum number of array items (effective when type is array) | number | — |
| gutter | Grid spacing | number | 0 |
| justify | Horizontal alignment under flex layout | start / end / center / space-around / space-between / space-evenly | — |
| align | Vertical alignment under flex layout | top / middle /bottom | — |
| v-model:activeCollapse | Expanded collapse items (effective when type is collapse) | array | — |
| label-position | Position of form field labels. When set to left or right, you also need to set label-width | enum | right |
| label-width | Label width, e.g. '50px'. Form-items that are direct children of Form inherit this value. auto can be used. | string / number | '' |
| label-suffix | Suffix of the form field label | string | '' |
| hide-required-asterisk | Whether to hide the red asterisk next to required field labels | boolean | false |
| require-asterisk-position | Position of the asterisk | left / right | left |
| show-message | Whether to display validation error messages | boolean | true |
| inline-message | Whether to display validation messages inline | boolean | false |
| status-icon | Whether to display validation result feedback icons in the input box | boolean | false |
| validate-on-rule-change | Whether to trigger a validation immediately after the rules attribute changes | boolean | true |
| size | Size used to control the components within this form | large / default / small | — |
| disabled | Whether to disable all components in this form. If set to true, it overrides internal components' disabled | boolean | false |
| scroll-to-error | Scroll to the first erroneous form item when validation fails | boolean | false |
| scroll-into-view-options | When there are failed validation results, scroll to the first failed form item | object / boolean | — |
group Form Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| border-style | Set separator style | none / solid / hidden / dashed | solid |
| content-position | Position of the separator content | left / right / center | center |
array Form Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| max | Maximum number of form items | number | — |
step Form Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| process-status | Set the status of the current step | wait / process / finish / error / success | process |
| finish-status | Set the status of the finish step | wait / process / finish / error / success | finish |
| align-center | Center alignment | boolean | true |
z-form Methods
| Name | Description | Type |
|---|---|---|
| validate | Validate the entire form. Accepts a callback function or returns a Promise. | Function |
| validateField | Validate a specific field. | Function |
| resetFields | Reset this form item, restore its value to the initial value, and remove the validation result | Function |
| scrollToField | Scroll to the specified field | Function |
| clearValidate | Clear the validation information of a certain field. | Function |
z-form Events
| Event Name | Description | Type |
|---|---|---|
| update:modelValue | Form item data | Function |
| update:activeCollapse | Expanded items of collapse form | Function |
| update:activeStep | Current step of step form | Function |
| collapse-change | Triggered when collapse changes | Function |
| next-step | Triggered when clicking next step | Function |
| previous-step | Triggered when clicking prev step | Function |
Common Form Column Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| component | Form item component | input / checkbox / select / radio / Any locally or globally registered component | — |
| field | Field name | string | — |
| fieldProps | component attributes | object | — |
| formItemProps | formItem attributes | object | — |
| label | Form label name | string / () => VNode | — |
| order | Form order | number | — |
| hide | Show / hide | boolean / (formData) => boolean | — |
| show | Show / hide using v-show | boolean / (formData) => boolean | — |
| slot | Custom content slot of form item | string | — |
| render | Custom content render of form item | () => VNode | — |
| required | Whether the field is required | boolean | — |
| rules | Validation rules of the field | boolean | — |
| error | Error message | string / () => VNode | — |
| tooltip | Tooltip message | string / () => VNode | — |
| extra | Extra information | string / () => VNode | — |
| children | Effective in form collapse mode, column array | array | — |
| span | Number of grid spaces occupied | number | — |
| offset | Number of grid spaces to the left | number | — |
| pull | Number of grid spaces moved to the left | number | — |
| push | Number of grid spaces moved to the right | boolean | — |
| xs | <768px responsive grid or grid props object | number / object | — |
| sm | ≥768px responsive grid or grid props object | number / object | — |
| md | ≥992px responsive grid or grid props object | number / object | — |
| lg | ≥1200px responsive grid or grid props object | number / object | — |
| xl | ≥1920px responsive grid or grid props object | number / object | — |
array Form Column Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| label | Label name | string / () => VNode | — |
| field | Field name | string | — |
| max | Maximum number of form items | number | — |
| children | Form items in the current step (all are common column attributes) | array | — |
step Form Column Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| label | Step title | string / () => VNode | — |
| icon | Icon for step mode | string / Component | — |
| description | Description for step mode | boolean | — |
| status | Step status for step mode | wait / process / finish / error / success | — |
| children | Form items in the current step (all are common column attributes) | array | — |
formItemProps Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
| tooltip | Tooltip text | string / () => VNode | — |
| extra | Extra information | string / () => VNode | — |
| colon | Colon | boolean | — |
| label | Label text | string / () => VNode | — |
| label-width | Label width, e.g. '50px'. auto can be used. | string / number | '' |
| required | Whether it is required. If not set, it will be confirmed according to the validation rules | boolean | — |
| rules | Form validation rules. See table below; more at async-validator | object | — |
| error | Prompt information when the form field validation fails. Setting this value will cause the form validation state to become error and display this error message. | string / () => VNode | — |
| show-message | Whether to display validation error messages | boolean | true |
| inline-message | Whether to display validation messages inline | string / boolean | '' |
| size | Default size of components under this form field | large / default / small | — |
| for | Same capability as the native label | string | — |
| validate-status | Validation status of formItem | error / validating / success | — |