Schema-based validation with schemaResolver
@mantine/form has built-in support for Standard Schema, a community specification implemented by many popular schema validation libraries including zod, valibot, and arktype. Use schemaResolver to validate forms with any Standard Schema-compliant library without extra resolver packages.
Sync and async schema validation
By default, schemaResolver returns a function that may return a Promise, since the Standard Schema specification allows async validation. Pass { sync: true } when you know your schema is synchronous (e.g., Zod, Valibot) to get synchronous return types for form.validate(), form.validateField(), and form.isValid().
zod schema validation example - basic field validation
import { z } from 'zod/v4';
import { useForm, schemaResolver } from '@mantine/form';
const schema = z.object({
name: z.string().min(2, { error: 'Name should have at least 2 letters' }),
email: z.email({ error: 'Invalid email' }),
age: z.number().min(18, { error: 'You must be at least 18 to create an account' }),
});
const form = useForm({
mode: 'uncontrolled',
initialValues: {
name: '',
email: '',
age: 16,
},
validate: schemaResolver(schema, { sync: true }),
});
form.validate();
form.errors;
// -> {
// name: 'Name should have at least 2 letters',
// email: 'Invalid email',
// age: 'You must be at least 18 to create an account'
// }
zod schema validation example - nested field validation
import { z } from 'zod/v4';
import { useForm, schemaResolver } from '@mantine/form';
const nestedSchema = z.object({
nested: z.object({
field: z.string().min(2, { error: 'Field should have at least 2 letters' }),
}),
});
const form = useForm({
mode: 'uncontrolled',
initialValues: {
nested: {
field: '',
},
},
validate: schemaResolver(nestedSchema, { sync: true }),
});
form.validate();
form.errors;
// -> {
// 'nested.field': 'Field should have at least 2 letters',
// }
zod schema validation example - list field validation
import { z } from 'zod/v4';
import { useForm, schemaResolver } from '@mantine/form';
const listSchema = z.object({
list: z.array(
z.object({
name: z.string().min(2, { error: 'Name should have at least 2 letters' }),
})
),
});
const form = useForm({
mode: 'uncontrolled',
initialValues: {
list: [{ name: '' }],
},
validate: schemaResolver(listSchema, { sync: true }),
});
form.validate();
form.errors;
// -> {
// 'list.0.name': 'Name should have at least 2 letters',
// }
zod schema validation example - async validation
import { z } from 'zod/v4';
import { useForm, schemaResolver } from '@mantine/form';
const schema = z
.object({
email: z.email({ error: 'Invalid email' }),
})
.refine(
async (data) => {
const isTaken = await checkEmailExists(data.email);
return !isTaken;
},
{ error: 'Email is already taken', path: ['email'] }
);
const form = useForm({
mode: 'uncontrolled',
initialValues: { email: '' },
validate: schemaResolver(schema),
});
// form.validate() returns a Promise
await form.validate();
Async validation returns promises
When using async validation with schemaResolver (without { sync: true }), the methods form.validate(), form.validateField(), and form.isValid() return promises instead of synchronous values.
Standard Schema supported libraries
Standard Schema is implemented by many popular schema validation libraries including zod, valibot, and arktype. The zod library is recommended as the most modern and developer-friendly choice.