Schema Libraries (Yup, Zod)
Optional - delegate validation to Yup, Zod, or any schema library from inside a gform-react custom validator. gform's native, custom, and async rules already cover every case.
gform-react validates everything on its own - native constraints, custom rules, and async checks cover every case without a schema library. Reach for Yup or Zod only if you already use one (e.g. a schema shared with your backend) and want a single source of truth.
Because custom validators are just functions, you can delegate to any schema library. Run the schema
inside withCustomValidation and map its result to gform's true-means-error contract.
Zod
import { z } from "zod";
import { GValidator, type GValidators } from "gform-react";
const emailSchema = z.string().email();
const validators: GValidators<Form> = {
email: new GValidator().withCustomValidation((input) => {
const result = emailSchema.safeParse(input.value);
if (!result.success) {
input.errorText = result.error.issues[0].message;
return true; // invalid
}
return false; // valid
}),
};Yup
Yup throws on failure, so map the catch to the same contract:
import { string } from "yup";
import { GValidator, type GValidators } from "gform-react";
const emailSchema = string().email("Enter a valid email").required("Required");
const validators: GValidators<Form> = {
email: new GValidator().withCustomValidation((input) => {
try {
emailSchema.validateSync(input.value);
return false; // valid
} catch (err) {
input.errorText = err.message;
return true; // invalid
}
}),
};For schema methods that return a promise (Zod's parseAsync, Yup's validate), use
withCustomValidationAsync instead - the same true-means-error
mapping applies to the resolved value.
The same pattern works with any validator you prefer - Valibot, Joi, a hand-written function - as
long as you set input.errorText and return true on failure.
Next
- Custom Validation - the
withCustomValidationcontract in full, including cross-field rules. - GValidator - execution order and the mutation gotcha.