Default Values and Validation
Setting default values and wiring required, custom, and schema-driven validation.
Default values
usePrismForm's second argument is passed straight through to React Hook Form's own useForm,
so defaultValues works exactly as it does in RHF:
const form = usePrismForm(definition, {
defaultValues: { name: '', email: '', age: 18, acceptTerms: false },
});FormValues (the generic on defineForm) determines the shape defaultValues must satisfy,
TypeScript rejects a missing or mistyped key the same way it would on a plain useForm call.
Required-field and native validation
PrismField accepts an optional rules prop, RHF's own RegisterOptions, passed straight
through to Controller:
<PrismField form={form} name="email" rules={{ required: 'Email is required' }} />This is the documented escape hatch for reaching RHF's native validation directly. For
schema-driven validation across an entire form, see the next section, most consumers prefer a
single Zod schema over per-field rules.
Schema-driven validation with Zod
@prismrepo/adapter-zod's createZodResolver adapts a Zod schema into the resolver shape
usePrismForm's options.resolver accepts:
import { z } from 'zod';
import { createZodResolver } from '@prismrepo/adapter-zod';
const schema = z.object({
name: z.string().min(1, 'Name is required'),
email: z.string().min(1, 'Email is required').email('Invalid email address'),
age: z.number().min(18, 'Must be at least 18 years old'),
});
const form = usePrismForm(definition, {
defaultValues: { name: '', email: '', age: 18 },
resolver: createZodResolver(schema),
});A failed validation surfaces through the exact same field.error every field component already
reads, there is no separate Zod-specific error channel. createZodResolver's input/output
types are inferred from the schema itself, not a hand-written generic parameter.
Custom validation
Custom, cross-field, or conditional validation is ordinary Zod: .refine() and
.superRefine() work exactly as they do with any other Zod schema, and the result still flows
through the same resolver:
const schema = z
.object({
password: z.string().min(8, 'At least 8 characters'),
confirmPassword: z.string(),
acceptTerms: z.boolean(),
})
.refine((data) => data.password === data.confirmPassword, {
message: 'Passwords must match',
path: ['confirmPassword'],
})
.refine((data) => data.acceptTerms === true, {
message: 'You must accept the terms',
path: ['acceptTerms'],
});A .refine() targeting a specific field via path surfaces its message through that field's
own field.error, the same as any other validation failure.
See Combining RHF and Zod for how resolver precedence works
when both rules and a Zod resolver are present on the same form, and
Zod Integration for the adapter's full API and version requirements.