Function: useZodForm()
useZodForm<
TSchema>(schema,options?):object
Defined in: packages/react/src/useZodForm.ts:83
React Hook Form integration hook for Zod v4 schemas.
Walks the schema to produce FormField[] and wires useForm with a
zodResolver. When options.optimization is set the zodResolver is
replaced by per-field validation (via schemaLite) and the resolver
import is tree-shaken in production builds.
Type Parameters
TSchema
TSchema extends ZodObject<$ZodLooseShape, $strip>
Parameters
schema
TSchema
The z.object({...}) schema to generate the form from.
options?
UseZodFormOptions<TSchema>
Optional hook configuration.
Returns
{ form, fields } — the RHF UseFormReturn and the FormField[] array.
fields
fields:
FormField[] =walkResult.fields
form
form:
UseFormReturn<output<TSchema>,any,output<TSchema>>
schemaError
schemaError:
string|null=walkResult.error
Non-null when walkSchema threw — lets consumers display the error instead of an empty form
schemaLite
schemaLite:
$ZodType<unknown,unknown,$ZodTypeInternals<unknown,unknown>> |null=walkResult.schemaLite
SchemaLite for submit-time validation (non-null when optimization is enabled and top-level effects exist)
Example
const { form, fields } = useZodForm(loginSchema);
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
{fields.map((f) => <input key={f.key} {...form.register(f.key)} />)}
</form>
);
Use When
- You need direct access to the RHF
forminstance (e.g. to callform.setValue) - You are building a custom renderer on top of
FormField[] - You want to colocate form state management with your own layout logic
Avoid When
- You just need a working form UI — use
<ZodForm>instead, which handles rendering - You are on Zod v3 — the hook requires Zod v4 schema internals
Pitfalls
- NEVER pass a new schema object on every render —
walkSchemais memoized by schema identity; an unstable reference causes re-walking on every render cycle - NEVER forget
normalizeFormValues()before manually callingschema.safeParse()— the hook's internal resolver applies normalization, but manual calls do not - NEVER mix
formRegistryandfieldsoptions on the same call — whenformRegistryis provided,fieldsis ignored entirely (no merge, no warning)