| name | rhf-zod-schema-integration |
| version | 1.0 |
| description | React Hook Form v7 with zodResolver integration for type-safe validated forms. PROACTIVELY activate for: (1) creating forms with useForm and zodResolver, (2) implementing field registration with spread syntax, (3) handling form state and errors. Triggers: "react hook form", "useForm", "zodResolver"
|
| group | state-forms |
| core-integration | {"techniques":{"primary":["structured_decomposition"],"secondary":[]},"contracts":{"input":"none","output":"none"},"patterns":"none","rubrics":"none"} |
React Hook Form + Zod Schema Integration
The Integration Pattern
React Hook Form v7 + Zod provides fully type-safe, validated forms:
'use client'
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
email: z.string().email('Invalid email'),
password: z.string().min(8, 'Minimum 8 characters'),
});
type FormData = z.infer<typeof schema>;
function MyForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<FormData>({
resolver: zodResolver(schema),
});
const onSubmit = (data: FormData) => {
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email')} />
{errors.email && <p>{errors.email.message}</p>}
<input type="password" {...register('password')} />
{errors.password && <p>{errors.password.message}</p>}
<button type="submit" disabled={isSubmitting}>Submit</button>
</form>
);
}
useForm Configuration
const {
register,
handleSubmit,
formState,
reset,
watch,
getValues,
setValue,
setError,
} = useForm<FormData>({
resolver: zodResolver(mySchema),
defaultValues: {
email: '',
password: '',
},
mode: 'onBlur',
reValidateMode: 'onChange',
});
Field Registration (v7 Spread Pattern)
<input {...register('fieldName')} />
<input name="fieldName" ref={register} />
Registration with Type Conversion
<input
type="number"
{...register('age', { valueAsNumber: true })}
/>
<input
type="date"
{...register('birthDate', { valueAsDate: true })}
/>
<input
type="checkbox"
{...register('acceptTerms')}
/>
Error Handling Patterns
Field-Level Errors
{errors.email && (
<p className="text-red-500 text-sm mt-1">
{errors.email.message}
</p>
)}
{errors.address?.street && (
<p>{errors.address.street.message}</p>
)}
{errors.items?.[index]?.name && (
<p>{errors.items[index]?.name?.message}</p>
)}
Form-Level Errors
const onSubmit = async (data: FormData) => {
try {
await api.submit(data);
} catch (error) {
setError('root', {
message: 'Submission failed. Please try again.',
});
}
};
{errors.root && (
<div className="bg-red-100 p-3 rounded">
{errors.root.message}
</div>
)}
Form State Management
const {
formState: {
errors,
isSubmitting,
isSubmitted,
isDirty,
isValid,
dirtyFields,
touchedFields,
},
} = useForm<FormData>();
<button
type="submit"
disabled={isSubmitting || !isDirty}
>
{isSubmitting ? 'Submitting...' : 'Submit'}
</button>
Complete Form Example
'use client'
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const signupSchema = z.object({
email: z.string().email('Invalid email address'),
password: z.string().min(8, 'Password must be at least 8 characters'),
confirmPassword: z.string(),
}).refine((data) => data.password === data.confirmPassword, {
message: 'Passwords do not match',
path: ['confirmPassword'],
});
type SignupFormData = z.infer<typeof signupSchema>;
export function SignupForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting, isDirty },
reset,
setError,
} = useForm<SignupFormData>({
resolver: zodResolver(signupSchema),
mode: 'onBlur',
defaultValues: {
email: '',
password: '',
confirmPassword: '',
},
});
const onSubmit = async (data: SignupFormData) => {
try {
const response = await fetch('/api/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
if (!response.ok) {
const error = await response.json();
setError('root', { message: error.message });
return;
}
reset();
alert('Signup successful!');
} catch (error) {
setError('root', { message: 'Network error. Please try again.' });
}
};
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4 max-w-md">
{errors.root && (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
{errors.root.message}
</div>
)}
<div>
<label htmlFor="email" className="block text-sm font-medium mb-1">
Email
</label>
<input
id="email"
type="email"
{...register('email')}
className="w-full px-3 py-2 border rounded-md"
/>
{errors.email && (
<p className="text-red-500 text-sm mt-1">{errors.email.message}</p>
)}
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium mb-1">
Password
</label>
<input
id="password"
type="password"
{...register('password')}
className="w-full px-3 py-2 border rounded-md"
/>
{errors.password && (
<p className="text-red-500 text-sm mt-1">{errors.password.message}</p>
)}
</div>
<div>
<label htmlFor="confirmPassword" className="block text-sm font-medium mb-1">
Confirm Password
</label>
<input
id="confirmPassword"
type="password"
{...register('confirmPassword')}
className="w-full px-3 py-2 border rounded-md"
/>
{errors.confirmPassword && (
<p className="text-red-500 text-sm mt-1">{errors.confirmPassword.message}</p>
)}
</div>
<button
type="submit"
disabled={isSubmitting || !isDirty}
className="w-full py-2 px-4 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:bg-gray-400"
>
{isSubmitting ? 'Creating account...' : 'Sign Up'}
</button>
</form>
);
}
Anti-Patterns
Mixing Validation Sources
const schema = z.object({ email: z.string().email() });
<input {...register('email', { required: 'Required' })} />
const schema = z.object({ email: z.string().email().min(1, 'Required') });
<input {...register('email')} />
Using v6 Registration
<input name="email" ref={register} />
<input {...register('email')} />
Summary
React Hook Form v7 + Zod integration provides:
- Type-safe forms with
z.infer<typeof schema>
- Automatic validation via
zodResolver
- v7 spread registration:
{...register('field')}
- Rich error handling with
errors object
- Form state management (isSubmitting, isDirty, isValid)
- No validation duplication - Zod is single source of truth
Related Skills: zod-schema-type-inference-chain, rhf-dynamic-field-arrays