Custom Plugins
Write your own plugin — transform values, add rules, gate submissions
Custom Plugins
Any plugin is an object with a unique name and any subset of lifecycle hooks (see the plugin shape on the Plugins overview page). Here are the three most common jobs.
Transform values on change
Return a new value from onChange to transform it (like a field-level normalizer):
const uppercaseNames = {
name: "uppercase-names",
priority: -10, // run before the built-in normalize plugin
onChange: ({ field, value }) =>
field === "firstName" || field === "lastName"
? String(value ?? "").toUpperCase()
: undefined,
};Return undefined to leave the value untouched.
Add a validation rule
Use validateField for cross-cutting checks that apply to any field:
const notPwned = {
name: "not-pwned",
validateField: ({ field, value }) =>
field === "password" && PWNED_LIST.includes(value)
? "This password appeared in a data breach"
: undefined,
};Gate submission with an API call
Use onSubmit to block submit (return false) and surface an error:
const verifyEmailOnSubmit = {
name: "verify-email",
onSubmit: async (values, helpers) => {
const res = await fetch(`/api/verify-email?email=${values.email}`);
const { ok } = await res.json();
if (!ok) {
helpers.setFieldError("email", "This email is not verified");
return false; // blocks submission
}
},
};Priority
priority orders plugins with the same hook — lower numbers run first (default 0). Use it to run your plugin before or after the built-ins (normalize, format).
Things to know
namemust be unique; a plugin namednormalizeorformatreplaces the built-in.ctxis{ values, field, value, fieldConfig, form }—formexposes the imperative helpers (setFieldValue,setFieldError,validateField, …).