Formily Lifecycle Events: Complete Guide to Form and Field Hooks

Formily exposes over 40 lifecycle events through the LifeCycleTypes enum in @formily/core, allowing you to hook into form initialization, validation, submission, and field-level changes using effect functions like onFormInit and onFieldValueChange.

The alibaba/formily library provides a comprehensive reactive form solution with granular lifecycle management. Understanding Formily lifecycle events is essential for building complex forms that require custom validation logic, asynchronous submissions, or dynamic field behavior. These events are defined in the LifeCycleTypes enum and exposed through convenient effect hooks that subscribe to form and field state changes.

Form Lifecycle Events

Form-level lifecycle events cover initialization, mounting, value changes, validation, and submission phases. In packages/core/src/types.ts, the LifeCycleTypes enum defines these events between lines 37-68.

Event Description
ON_FORM_INIT Form instance has been created.
ON_FORM_MOUNT Form has been mounted (e.g., after form.mount() or component mount).
ON_FORM_UNMOUNT Form is being unmounted.
ON_FORM_INPUT_CHANGE Any input value in the form changed (raw input before normalization).
ON_FORM_VALUES_CHANGE Normalized form values changed.
ON_FORM_INITIAL_VALUES_CHANGE Initial values of the form changed (usually via form.setInitialValues).
ON_FORM_SUBMIT Form submission started (no validation yet).
ON_FORM_RESET Form has been reset to its initial state.
ON_FORM_SUBMIT_START Submission lifecycle start (after validation).
ON_FORM_SUBMITTING While the submit async process is running.
ON_FORM_SUBMIT_END Submission finished (regardless of success/failure).
ON_FORM_SUBMIT_VALIDATE_START Validation that runs before submit begins.
ON_FORM_SUBMIT_VALIDATE_SUCCESS Validation succeeded before submit.
ON_FORM_SUBMIT_VALIDATE_FAILED Validation failed before submit.
ON_FORM_SUBMIT_VALIDATE_END End of the pre‑submit validation phase.
ON_FORM_SUBMIT_SUCCESS Submit async handler resolved successfully.
ON_FORM_SUBMIT_FAILED Submit async handler rejected.
ON_FORM_VALIDATE_START General validation start (e.g., form.validate()).
ON_FORM_VALIDATING Validation is in progress.
ON_FORM_VALIDATE_SUCCESS Validation succeeded.
ON_FORM_VALIDATE_FAILED Validation failed.
ON_FORM_VALIDATE_END Validation cycle finished.
ON_FORM_GRAPH_CHANGE Internal form graph (dependency tree) changed.
ON_FORM_LOADING Form enters a loading state.

Field Lifecycle Events

Field-level events allow you to react to individual input changes, validation states, and UI mounting operations. These constants are defined in LifeCycleTypes at lines 71-98 of packages/core/src/types.ts.

Event Description
ON_FIELD_INIT Field instance has been created.
ON_FIELD_INPUT_VALUE_CHANGE Raw input value of the field changed.
ON_FIELD_VALUE_CHANGE Normalized field value changed.
ON_FIELD_INITIAL_VALUE_CHANGE Field's initial value changed.
ON_FIELD_SUBMIT Field participates in form submit (e.g., value collected).
ON_FIELD_SUBMIT_START Submit phase start for the field.
ON_FIELD_SUBMITTING Field is being submitted asynchronously.
ON_FIELD_SUBMIT_END Submit phase end for the field.
ON_FIELD_SUBMIT_VALIDATE_START Validation before submit for the field.
ON_FIELD_SUBMIT_VALIDATE_SUCCESS Field validation succeeded before submit.
ON_FIELD_SUBMIT_VALIDATE_FAILED Field validation failed before submit.
ON_FIELD_SUBMIT_VALIDATE_END End of field‑pre‑submit validation.
ON_FIELD_SUBMIT_SUCCESS Field submit succeeded.
ON_FIELD_SUBMIT_FAILED Field submit failed.
ON_FIELD_VALIDATE_START Field validation start (independent of submit).
ON_FIELD_VALIDATING Field is currently validating.
ON_FIELD_VALIDATE_SUCCESS Field validation succeeded.
ON_FIELD_VALIDATE_FAILED Field validation failed.
ON_FIELD_VALIDATE_END Field validation cycle finished.
ON_FIELD_LOADING Field enters a loading state.
ON_FIELD_RESET Field has been reset to its initial value.
ON_FIELD_MOUNT Field has been mounted in the UI.
ON_FIELD_UNMOUNT Field has been removed from the UI.

Implementing Lifecycle Hooks

Instead of manually subscribing to LifeCycleTypes enum values, Formily provides ergonomic helper functions exported from packages/core/src/effects/onFormEffects.ts. These wrappers handle the subscription logic internally.

Form-Level Hooks

import {
  onFormInit,
  onFormValuesChange,
  onFormSubmitStart,
  onFormSubmitEnd,
  onFormValidateFailed,
} from '@formily/core';

// Log when a form is created
onFormInit((form) => {
  console.log('Form created →', form);
});

// React to normalized value changes
onFormValuesChange((form) => {
  console.log('Form values changed →', form.values);
});

// Submit lifecycle monitoring
onFormSubmitStart((form) => {
  console.log('Submitting…');
});

onFormSubmitEnd((form, result) => {
  console.log('Submit finished, result:', result);
});

onFormValidateFailed((form, errors) => {
  console.error('Form validation failed:', errors);
});

Field-Level Hooks

import {
  onFieldInit,
  onFieldValueChange,
  onFieldValidateStart,
  onFieldValidateFailed,
  onFieldSubmitSuccess,
} from '@formily/core';

// Target specific fields by path
onFieldInit((field) => {
  if (field.path?.toString() === 'username') {
    console.log('Username field initialized');
  }
});

// Monitor value changes
onFieldValueChange((field) => {
  if (field.path?.toString() === 'age') {
    console.log('Age changed to', field.value);
  }
});

// Validation lifecycle
onFieldValidateStart((field) => {
  console.log(`Validating ${field.path}`);
});

onFieldValidateFailed((field, errors) => {
  console.warn(`Field ${field.path} validation errors:`, errors);
});

// Submit success for specific field
onFieldSubmitSuccess((field, result) => {
  console.log(`Field ${field.path} submitted successfully`, result);
});

Core Implementation Architecture

Lifecycle events are dispatched through the notify method implemented in the core models. When you register a hook, it internally subscribes to notifications fired by these methods.

The Form class implements Form.notify in packages/core/src/models/Form.ts (lines 304-330). This method broadcasts events to all registered listeners for form-level lifecycle types.

Fields use BaseField.notify defined in packages/core/src/models/BaseField.ts (lines 305-317). The concrete Field class in packages/core/src/models/Field.ts inherits this behavior to trigger field-specific events.

When form.notify(LifeCycleTypes.ON_FORM_VALUES_CHANGE) executes during a state update, all callbacks registered via onFormValuesChange receive the form instance as an argument. Similarly, field.notify(LifeCycleTypes.ON_FIELD_VALUE_CHANGE) invokes listeners registered through onFieldValueChange.

Summary

  • Formily lifecycle events are defined as constants in the LifeCycleTypes enum located in packages/core/src/types.ts
  • Form events cover initialization (ON_FORM_INIT), mounting (ON_FORM_MOUNT), submission phases (ON_FORM_SUBMIT_START, ON_FORM_SUBMIT_END), and validation cycles (ON_FORM_VALIDATE_START, ON_FORM_VALIDATE_SUCCESS, ON_FORM_VALIDATE_FAILED)
  • Field events provide granular control over individual inputs (ON_FIELD_INPUT_VALUE_CHANGE), normalized values (ON_FIELD_VALUE_CHANGE), and field-specific validation states
  • Effect helpers like onFormInit and onFieldValueChange from @formily/core provide type-safe subscriptions without referencing raw enum values
  • Event dispatching occurs through Form.notify() and BaseField.notify() methods in their respective model classes, triggering all registered callbacks asynchronously

Frequently Asked Questions

What is the difference between ON_FORM_INPUT_CHANGE and ON_FORM_VALUES_CHANGE?

ON_FORM_INPUT_CHANGE fires when raw input values change before any normalization or formatting occurs, while ON_FORM_VALUES_CHANGE fires after the values have been processed and normalized. Use the former to intercept user input immediately, and the latter to react to final data state changes.

How do I listen to lifecycle events for a specific field only?

Filter by the path property inside your callback function. Both form and field hooks receive the target instance as an argument, allowing you to check field.path.toString() or field.path.toArr() before executing logic, as shown in the field-level examples targeting username and age fields.

What is the execution order of submission lifecycle events?

The sequence follows: ON_FORM_SUBMIT (initial trigger) → ON_FORM_SUBMIT_VALIDATE_START (validation begins) → ON_FORM_SUBMIT_VALIDATE_SUCCESS or ON_FORM_SUBMIT_VALIDATE_FAILEDON_FORM_SUBMIT_START (post-validation) → ON_FORM_SUBMITTING (async operation) → ON_FORM_SUBMIT_SUCCESS or ON_FORM_SUBMIT_FAILEDON_FORM_SUBMIT_END (final cleanup).

Where are lifecycle events implemented in the Formily source code?

Event constants reside in packages/core/src/types.ts (the LifeCycleTypes enum). The notification mechanism is implemented in packages/core/src/models/Form.ts for forms and packages/core/src/models/BaseField.ts for fields, specifically in the notify methods that iterate through registered listeners when state changes occur.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →