Hey, devs...
Conditional validation is essential when your form logic depends on other fields. In this article, you'll learn how to apply it using Yup and Zod, with complete examples in React.
✅ What is Conditional Validation?
It's when the validation of a field depends on the value of another. Example: if the user checks that they are a student, the minimum required age might be different.
📦 Example with Yup
import * as yup from 'yup';
const schema = yup.object().shape({
isStudent: yup.boolean(),
age: yup.number().when('isStudent', {
is: true,
then: yup.number().required().min(18),
otherwise: yup.number().min(12),
}),
});
Explanation:
- when('isStudent', {...}): defines the conditional logic based on the isStudent field.
- then: requires a minimum age of 18 if the user is a student.
- otherwise: requires a minimum age of 12 if not a student.
Example with Zod
import { z } from 'zod';
const baseSchema = z.object({
isStudent: z.boolean(),
age: z.number(),
});
const schema = baseSchema.superRefine((data, ctx) => {
if (data.isStudent && data.age < 18) {
ctx.addIssue({
path: ['age'],
code: z.ZodIssueCode.too_small,
minimum: 18,
type: 'number',
inclusive: true,
message: 'Students must be at least 18 years old',
});
} else if (!data.isStudent && data.age < 12) {
ctx.addIssue({
path: ['age'],
code: z.ZodIssueCode.too_small,
minimum: 12,
type: 'number',
inclusive: true,
message: 'Minimum age is 12',
});
}
});
Comparison: Yup vs Zod
Feature | Yup | Zod |
---|---|---|
Direct conditional syntax | ✅ Yes (when ) |
❌ No (uses superRefine ) |
TypeScript support | Partial (needs yup.InferType ) |
Full and native |
Custom error messages | Yes | Yes |
Learning curve | Easier for beginners | More powerful, but more verbose |
Performance | Good | Excellent |
Full Example with React
Form with Formik + Yup
npm install formik yup
Code
import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
const validationSchema = Yup.object().shape({
isStudent: Yup.boolean(),
age: Yup.number().when('isStudent', {
is: true,
then: Yup.number().required('Required').min(18, 'Student must be at least 18'),
otherwise: Yup.number().min(13, 'Minimum age is 12'),
}),
});
export default function FormYup() {
return (
<Formik
initialValues={{ isStudent: false, age: '' }}
validationSchema={validationSchema}
onSubmit={(values) => alert(JSON.stringify(values, null, 2))}
>
{({ values }) => (
<Form>
<label>
<Field type="checkbox" name="isStudent" />
I am a student
</label>
<div>
<label>Age:</label>
<Field type="number" name="age" />
<ErrorMessage name="age" component="div" style={{ color: 'red' }} />
</div>
<button type="submit">Submit</button>
</Form>
)}
</Formik>
);
}
Form with React Hook Form + Zod
Instalation
npm install react-hook-form zod @hookform/resolvers
Code
import React from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
const baseSchema = z.object({
isStudent: z.boolean(),
age: z.number({ required_error: 'Please enter your age' }),
});
const schema = baseSchema.superRefine((data, ctx) => {
if (data.isStudent && data.age < 18) {
ctx.addIssue({
path: ['age'],
code: z.ZodIssueCode.too_small,
minimum: 18,
type: 'number',
inclusive: true,
message: 'Student must be at least 18',
});
} else if (!data.isStudent && data.age < 12) {
ctx.addIssue({
path: ['age'],
code: z.ZodIssueCode.too_small,
minimum: 12,
type: 'number',
inclusive: true,
message: 'Minimum age is 13',
});
}
});
export default function FormZod() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: zodResolver(schema),
defaultValues: { isStudent: false, age: 0 },
});
const onSubmit = (data) => alert(JSON.stringify(data, null, 2));
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>
<input type="checkbox" {...register('isStudent')} />
I am a student
</label>
<div>
<label>Age:</label>
<input type="number" {...register('age', { valueAsNumber: true })} />
{errors.age && <p style={{ color: 'red' }}>{errors.age.message}</p>}
</div>
<button type="submit">Submit</button>
</form>
);
}
Conclusion
- Use Yup if you want a simpler and more declarative syntax.
- Use Zod if you're working with TypeScript and want more control and performance.
Both libraries are powerful - the best choice depends on your project and preferences.
Top comments (3)
Thanku for share this.
enjoy
that's what I needed