How to Validate Forms with Custom Validation Rules in Element UI
You can validate forms with custom validation rules in Element UI by supplying rule objects to the rules prop of <el-form> or <el-form-item>, which are then processed by the internal AsyncValidator engine.
Element UI (ElemeFE/element) provides a robust form validation system that allows developers to validate forms with custom validation rules using both form-level and form-item-level configurations. The validation engine leverages the async-validator library to execute rules based on triggers like blur or change.
Understanding the Validation Architecture
The validation system combines three distinct sources of rules, defined in packages/form/src/form.vue and packages/form/src/form-item.vue.
Form-Level Rules
In packages/form/src/form.vue at lines 24-26, the rules prop accepts an object mapping field names to rule arrays:
rules: {
type: Object,
default: null
}
These rules are injected into all child <el-form-item> components via Vue's provide/inject pattern, making them available for every field in the form.
Form-Item-Level Rules
Individual fields can override or extend form-level rules using the rules prop defined at lines 70-71 of packages/form/src/form-item.vue:
rules: {
type: [Object, Array],
default: null
}
Additionally, the required prop (lines 66-69) provides a shortcut that automatically generates a { required: true } rule when set to true.
How Custom Validation Rules Work
When validation triggers, the FormItem component executes a multi-step process defined in packages/form/src/form-item.vue.
The Rule Merging Process
The getRules() method (lines 57-66) concatenates three rule sources in order:
- Form-level rules for the specific
propname - Form-item-level
rulesprop - Auto-generated rule if
requiredistrue
This creates a comprehensive rule array that respects both global and local configurations.
Trigger-Based Filtering
Before execution, getFilteredRule(trigger) (lines 67-78) filters the merged rules based on their trigger property. This ensures that blur rules only run on blur events and change rules only run on change events, optimizing performance and user experience.
AsyncValidator Execution
The actual validation occurs in the validate() method (lines 94-124):
- Descriptor creation: Rules are assigned to a descriptor object where the key is the field
prop - Validation: An
AsyncValidatorinstance processes the currentfieldValueagainst the descriptor - State management: On success,
validateStatebecomes'success'; on failure, it becomes'error'with the message stored invalidateMessage - Event emission: The field emits
'validate'to the parent form for result aggregation
Implementing Custom Validation Rules
Form-Level Custom Validators
Define complex validation logic in the form's rules object using the validator function:
<template>
<el-form :model="form" :rules="rules" ref="myForm">
<el-form-item label="Username" prop="username">
<el-input v-model="form.username" />
</el-form-item>
<el-button @click="submit">Submit</el-button>
</el-form>
</template>
<script>
export default {
data() {
return {
form: { username: '' },
rules: {
username: [
{ required: true, message: 'Username is required', trigger: 'blur' },
{
validator: (rule, value, callback) => {
const ok = /^[a-zA-Z0-9_]+$/.test(value);
ok ? callback() : callback(new Error('Only letters, numbers, and _ are allowed'));
},
trigger: 'blur'
}
]
}
};
},
methods: {
submit() {
this.$refs.myForm.validate(valid => {
if (valid) alert('Validation passed');
});
}
}
};
</script>
Item-Level Custom Validators
Override form-level rules or add field-specific validation using the rules prop on individual items:
<template>
<el-form :model="user" :rules="formRules">
<el-form-item label="Email" prop="email">
<el-input v-model="user.email" />
</el-form-item>
<el-form-item label="Password" prop="password" :rules="passwordRules">
<el-input type="password" v-model="user.password" />
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
user: { email: '', password: '' },
formRules: {
email: [{ required: true, message: 'Email required', trigger: 'blur' }]
},
passwordRules: [
{ required: true, message: 'Password required', trigger: 'blur' },
{
validator: (rule, value, cb) => {
setTimeout(() => {
const strong = /^(?=.*[A-Z])(?=.*\d).{8,}$/.test(value);
strong ? cb() : cb(new Error('Weak password'));
}, 300);
},
trigger: 'blur'
}
]
};
}
};
</script>
Using the Required Shortcut
For simple presence validation, use the required boolean prop instead of writing a rule object:
<el-form-item label="Phone" prop="phone" :required="true">
<el-input v-model="contact.phone" />
</el-form-item>
When required is set to true, FormItem.getRules() automatically injects { required: true } into the validation chain (lines 60-61 of packages/form/src/form-item.vue).
Programmatic Validation Control
Beyond declarative rules, the components expose methods for manual validation management.
Triggering Validation Manually
Call validate() on the form instance to check all fields:
this.$refs.formRef.validate((valid, fields) => {
if (valid) {
console.log('Submit form');
} else {
console.log('Validation failed', fields);
}
});
Clearing Validation State
Remove error messages without resetting values:
this.$refs.formRef.clearValidate();
// Or for a specific field
this.$refs.formItemRef.clearValidate();
Resetting Fields
Restore fields to their initial values and clear validation:
this.$refs.formRef.resetFields();
Dynamic Rule Changes
Set validateOnRuleChange to false (lines 41-44 of packages/form/src/form.vue) to prevent automatic re-validation when the rules object changes:
<el-form :rules="dynamicRules" :validate-on-rule-change="false">
<!-- fields -->
</el-form>
Summary
- Form-level rules defined in
packages/form/src/form.vue(lines 24-26) provide global validation logic injected into all child components. - Form-item-level rules in
packages/form/src/form-item.vue(lines 70-71) allow field-specific overrides and extensions. - Rule merging occurs in
FormItem.getRules()(lines 57-66), concatenating form rules, item rules, and therequiredshortcut. - Trigger filtering via
getFilteredRule()(lines 67-78) ensures rules only execute on specified events (blur,change). - AsyncValidator handles the actual validation logic in
FormItem.validate()(lines 94-124), managing success/error states and emitting events to the parent form.
Frequently Asked Questions
How do I trigger validation on blur versus change events?
Use the trigger property in your rule definition. Set trigger: 'blur' to validate when the field loses focus, or trigger: 'change' to validate when the value changes. The getFilteredRule(trigger) method in packages/form/src/form-item.vue (lines 67-78) filters rules based on this property, ensuring only matching triggers execute during validation events.
Can I use async validators in Element UI forms?
Yes, the validation engine supports asynchronous validation through the async-validator library. Supply a validator function that accepts a callback as its third argument, and call callback() for success or callback(new Error('message')) for failure. For async operations like API calls, execute the logic inside the validator and invoke the callback when the operation completes, as shown in the password validation example using setTimeout.
How do I reset validation errors programmatically?
Call the clearValidate() method on either the form instance or individual form-item instances. For the entire form, use this.$refs.formRef.clearValidate(). To reset a specific field, reference the form-item directly. This method clears the validateState and validateMessage properties without modifying the field values. To reset both values and validation states, use resetFields() instead.
What is the difference between form-level and form-item-level rules?
Form-level rules, defined on the <el-form> component's rules prop (lines 24-26 of packages/form/src/form.vue), apply globally to all fields with matching prop names and are injected into child components. Form-item-level rules, defined on individual <el-form-item> components (lines 70-71 of packages/form/src/form-item.vue), override or extend form-level rules for specific fields. When validation runs, FormItem.getRules() (lines 57-66) merges both sources, with form-item rules taking precedence in the concatenation order.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →