# How to Validate Forms with Custom Validation Rules in Element UI

> Learn to validate forms with custom validation rules in Element UI. Use the rules prop on el-form and el-form-item for powerful form validation.

- Repository: [饿了么前端/element](https://github.com/ElemeFE/element)
- Tags: how-to-guide
- Published: 2026-03-07

---

**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`](https://github.com/ElemeFE/element/blob/main/packages/form/src/form.vue) and [`packages/form/src/form-item.vue`](https://github.com/ElemeFE/element/blob/main/packages/form/src/form-item.vue).

### Form-Level Rules

In [`packages/form/src/form.vue`](https://github.com/ElemeFE/element/blob/main/packages/form/src/form.vue) at lines 24-26, the `rules` prop accepts an object mapping field names to rule arrays:

```javascript
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`](https://github.com/ElemeFE/element/blob/main/packages/form/src/form-item.vue):

```javascript
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`](https://github.com/ElemeFE/element/blob/main/packages/form/src/form-item.vue).

### The Rule Merging Process

The `getRules()` method (lines 57-66) concatenates three rule sources in order:

1. Form-level rules for the specific `prop` name
2. Form-item-level `rules` prop
3. Auto-generated rule if `required` is `true`

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):

1. **Descriptor creation**: Rules are assigned to a descriptor object where the key is the field `prop`
2. **Validation**: An `AsyncValidator` instance processes the current `fieldValue` against the descriptor
3. **State management**: On success, `validateState` becomes `'success'`; on failure, it becomes `'error'` with the message stored in `validateMessage`
4. **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:

```vue
<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:

```vue
<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:

```vue
<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`](https://github.com/ElemeFE/element/blob/main/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:

```javascript
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:

```javascript
this.$refs.formRef.clearValidate();
// Or for a specific field
this.$refs.formItemRef.clearValidate();

```

### Resetting Fields

Restore fields to their initial values and clear validation:

```javascript
this.$refs.formRef.resetFields();

```

### Dynamic Rule Changes

Set `validateOnRuleChange` to `false` (lines 41-44 of [`packages/form/src/form.vue`](https://github.com/ElemeFE/element/blob/main/packages/form/src/form.vue)) to prevent automatic re-validation when the `rules` object changes:

```vue
<el-form :rules="dynamicRules" :validate-on-rule-change="false">
  <!-- fields -->
</el-form>

```

## Summary

- **Form-level rules** defined in [`packages/form/src/form.vue`](https://github.com/ElemeFE/element/blob/main/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`](https://github.com/ElemeFE/element/blob/main/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 the `required` shortcut.
- **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`](https://github.com/ElemeFE/element/blob/main/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`](https://github.com/ElemeFE/element/blob/main/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`](https://github.com/ElemeFE/element/blob/main/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.