# How Formily's Validation System Works: Trigger Types and Implementation

> Explore Formily's validation system trigger types onInput onFocus onBlur and custom strings Understand how rules trigger Validation and enhance your forms

- Repository: [Alibaba/formily](https://github.com/alibaba/formily)
- Tags: internals
- Published: 2026-02-24

---

**Formily's validation system executes validator rules based on trigger types—`onInput`, `onFocus`, `onBlur`, or custom strings—by matching the trigger parameter in `validateSelf` against each rule's `triggerType` property.**

The Formily validation system, as implemented in the `alibaba/formily` repository, provides a flexible architecture for executing field-level and form-level validation based on user interaction patterns. Understanding how trigger types control when validation runs is essential for building responsive forms that provide timely feedback without overwhelming users.

## Core Architecture of Formily's Validation System

Formily's validation pipeline follows a three-stage process: descriptor parsing, rule normalization, and trigger-based execution. This architecture separates the definition of validation rules from their execution context.

### Validator Descriptor Parsing

Validation begins with **validator descriptors** that are normalized by the parser utilities in [`packages/validator/src/parser.ts`](https://github.com/alibaba/formily/blob/main/packages/validator/src/parser.ts). The `parseValidatorDescription` and `parseValidatorDescriptions` functions (lines 21-44) transform string, function, or object descriptors into standardized `IValidatorRules` objects. Each rule object may optionally include a `triggerType` field that specifies when the validation should execute.

### Rule-to-Function Conversion

Once parsed, `parseValidatorRules` (lines 46-70) walks through the rule keys and retrieves built-in validator functions from the internal registry. Each validator is wrapped with a consistent asynchronous wrapper (`createValidate`) that normalizes return values into `IValidateResult` objects containing error messages, warnings, or success states. This wrapping ensures that all validators—whether synchronous or asynchronous—return a consistent Promise-based interface.

## How Trigger Types Control Validation Execution

The execution of validation rules is orchestrated by the `validateSelf` function in [`packages/core/src/shared/internals.ts`](https://github.com/alibaba/formily/blob/main/packages/core/src/shared/internals.ts). This function implements the trigger-matching logic that determines which validators run during any given validation cycle.

### The Trigger Type Definition

Trigger types are defined as a TypeScript union type in [`packages/validator/src/types.ts`](https://github.com/alibaba/formily/blob/main/packages/validator/src/types.ts) (lines 49-53). The system recognizes the following **standard trigger types**:

- **`onInput`** – Validates whenever the field value changes (default behavior)
- **`onFocus`** – Validates when the field receives focus
- **`onBlur`** – Validates when the field loses focus
- **Custom strings** – Any user-defined string value (e.g., `onSubmit`, `onChange`) for application-specific validation timing

### validateSelf Implementation Details

The `validateSelf` function implements two distinct execution modes based on the presence of a `triggerType` argument:

1. **Auto-collection mode** (lines 62-70): When called without an explicit trigger, the function gathers all unique trigger types present in the field's validator list and executes validation for each type sequentially.

2. **Specific trigger mode** (lines 82-84): When a specific `triggerType` is supplied (e.g., `'onBlur'`), only validators whose `triggerType` property matches the supplied value execute.

### Field Lifecycle Integration

Field components in [`packages/core/src/models/Field.ts`](https://github.com/alibaba/formily/blob/main/packages/core/src/models/Field.ts) automatically invoke `validateSelf` through lifecycle hooks that map to DOM events:

- **`onInput`** (lines 84-85): Called on every value change
- **`onFocus`** (lines 88-94): Called when the input receives focus
- **`onBlur`** (lines 97-102): Called when the input loses focus

Each method calls `validateSelf(this, '<event>')`, passing the field instance and the trigger type string that corresponds to the interaction.

## Supported Trigger Types in Formily

Formily supports four categories of validation triggers that provide granular control over when feedback appears:

**`onInput` (Default)**
Validation runs continuously as the user types. This is the default behavior when no `triggerType` is specified in a validator rule, providing immediate feedback but potentially showing errors while the user is still entering data.

**`onFocus`**
Validation executes when the user clicks or tabs into a field. This trigger is useful for displaying contextual help or pre-validation warnings before the user begins typing.

**`onBlur`**
Validation runs when the user leaves the field. This pattern reduces noise during typing while ensuring data quality before the user moves to the next field.

**Custom Triggers**
Any string value can be used as a trigger type. Developers define custom triggers like `onSubmit` or `onStepChange` and manually invoke `form.validate({ triggerType: 'customName' })` to execute specific validation sets on demand.

## Practical Implementation Examples

### Basic Field with Default onInput Validation

The following example demonstrates the default behavior where validation runs on every keystroke:

```tsx
import { createForm, FormProvider, Field } from '@formily/react';

const form = createForm();

<FormProvider form={form}>
  <Field
    name="email"
    validator={{
      format: 'email',
      required: true,
      // triggerType omitted → defaults to 'onInput'
    }}
  >
    {(field) => (
      <input
        value={field.value}
        onChange={field.onInput}
      />
    )}
  </Field>
</FormProvider>

```

### Delayed Validation with onBlur

To validate only when the user finishes editing, specify `triggerType: 'onBlur'`:

```tsx
<Field
  name="username"
  validator={{
    validator: (value) => value?.length >= 4 ? '' : 'Username must be at least 4 characters',
    triggerType: 'onBlur',
  }}
>
  {(field) => (
    <>
      <input 
        value={field.value} 
        onChange={field.onInput}
        onBlur={field.onBlur} 
      />
      {field.errors?.map(err => <span key={err} className="error">{err}</span>)}
    </>
  )}
</Field>

```

### Form-Level Validation with Specific Triggers

The `batchValidate` function in [`packages/core/src/shared/internals.ts`](https://github.com/alibaba/formily/blob/main/packages/core/src/shared/internals.ts) supports trigger propagation from form-level calls:

```ts
// Validate only onBlur rules across all fields
await form.validate({ triggerType: 'onBlur' });

```

### Implementing Custom Trigger Types

Define application-specific validation timing using custom strings:

```ts
const secretRule = {
  validator: (value) => value === 'secret-token' ? '' : 'Invalid access token',
  triggerType: 'onVerify',
};

// Later in your component
await form.validate({ triggerType: 'onVerify' });

```

## Summary

- **Formily's validation system** uses `parseValidatorDescriptions` in [`packages/validator/src/parser.ts`](https://github.com/alibaba/formily/blob/main/packages/validator/src/parser.ts) to normalize validator descriptors into executable rules.
- **Trigger types** are defined in [`packages/validator/src/types.ts`](https://github.com/alibaba/formily/blob/main/packages/validator/src/types.ts) as `onInput`, `onFocus`, `onBlur`, or custom string values.
- **`validateSelf`** in [`packages/core/src/shared/internals.ts`](https://github.com/alibaba/formily/blob/main/packages/core/src/shared/internals.ts) filters validators by matching the supplied trigger against each rule's `triggerType` property.
- **Field lifecycle methods** (`onInput`, `onFocus`, `onBlur`) in [`packages/core/src/models/Field.ts`](https://github.com/alibaba/formily/blob/main/packages/core/src/models/Field.ts) automatically invoke validation with their respective trigger types.
- **Form-level validation** via `form.validate()` supports trigger filtering, allowing batch execution of specific validation sets.

## Frequently Asked Questions

### What is the default trigger type in Formily?

The default trigger type is **`onInput`**. When you define a validator without explicitly specifying a `triggerType` property, Formily executes that validator whenever the field value changes, corresponding to the `onInput` event.

### How do I run validation only on specific events?

Pass a `triggerType` option to `form.validate()` or define the `triggerType` property in your validator rules. For example, `await form.validate({ triggerType: 'onBlur' })` executes only validators configured with `triggerType: 'onBlur'`, while setting `triggerType: 'onBlur'` in a field validator ensures that rule only runs when the field loses focus.

### Can I define custom trigger types in Formily?

Yes, Formily accepts any string value as a `triggerType`. The `ValidatorTriggerType` in [`packages/validator/src/types.ts`](https://github.com/alibaba/formily/blob/main/packages/validator/src/types.ts) is an open union type that includes `onInput`, `onFocus`, and `onBlur`, but you can pass custom strings like `'onSubmit'` or `'onSave'`. You must manually invoke `form.validate({ triggerType: 'yourCustomTrigger' })` to execute validators using custom triggers.

### Where does Formily store the validation logic for fields?

Validation logic is stored in the field's `validator` property as normalized rules. The actual execution logic resides in [`packages/core/src/shared/internals.ts`](https://github.com/alibaba/formily/blob/main/packages/core/src/shared/internals.ts) (`validateSelf` and `batchValidate` functions), while the parsing and rule creation utilities are located in [`packages/validator/src/parser.ts`](https://github.com/alibaba/formily/blob/main/packages/validator/src/parser.ts). The field models in [`packages/core/src/models/Field.ts`](https://github.com/alibaba/formily/blob/main/packages/core/src/models/Field.ts) provide the lifecycle hooks that initiate validation based on user interactions.