- Published on
Validating Dates with ZOD and React
- Authors
- Name
- Ripal & Zalak
How to Validate Start and End Dates Using Zod
Date validation is a common requirement in many applications. In this post, we’ll explore how to validate dates dynamically in React forms using Zod for schema validation. Specifically, we'll ensure:
- Start date cannot be in the past.
- End date must be after the start date.
Problem Statement
When building a vacation app, we need a form where users input:
- Start date (must be in the future).
- End date (must be after the start date).
Basic validation can be implemented in TypeScript using error handling, but we aim to enhance the user experience by dynamically validating the input in the form itself, triggered on onBlur
events.
The Solution
We’ll use Zod for schema validation and React with react-hook-form
for form handling. Below is the implementation.
Code Example
Step 1: Install Dependencies
Install the necessary libraries:
npm install zod react-hook-form @hookform/resolvers
Step 2: Create the Form Component
import React from 'react'
import { useForm } from 'react-hook-form'
import { z, ZodType } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'
function AddVacation(): JSX.Element {
type FormData = {
startDate: Date
endDate: Date
}
// Define the schema
const schema: ZodType<FormData> = z
.object({
startDate: z.coerce.date().refine((date) => date > new Date(), {
message: 'Start date must be in the future',
}),
endDate: z.coerce.date(),
})
.refine((data) => data.endDate > data.startDate, {
message: 'End date must be after start date',
path: ['endDate'],
})
const {
register,
handleSubmit,
trigger,
formState: { errors },
} = useForm<FormData>({ resolver: zodResolver(schema) })
const onSubmit = (data: FormData) => {
console.log('Form submitted:', data)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label htmlFor="startDate">Start Date</label>
<input type="date" {...register('startDate')} onBlur={() => trigger('startDate')} />
{errors.startDate && <p>{errors.startDate.message}</p>}
</div>
<div>
<label htmlFor="endDate">End Date</label>
<input type="date" {...register('endDate')} onBlur={() => trigger('endDate')} />
{errors.endDate && <p>{errors.endDate.message}</p>}
</div>
<button type="submit">Add Vacation</button>
</form>
)
}
export default AddVacation
FAQs
zod.coerce.date()
?
1. Why use - It converts strings (from input fields) to
Date
objects, ensuring type safety during validation.
.refine()
do?
2. What does - The
.refine()
method allows custom validation logic. In this example, it ensures the start date is in the future and the end date is after the start date.
3. Can I use Material-UI’s Date Picker?
- Yes! Replace the
<input type="date" />
with MUI’s<DatePicker />
and integrate it withreact-hook-form
using theController
component.
Key Takeaways
- Zod is a powerful tool for validating complex logic in forms.
- Combining Zod with
react-hook-form
ensures a smooth user experience with instant feedback. - Custom validation logic can be added with
.refine()
to handle edge cases effectively.
Example Validation Cases
Input | Output |
---|---|
Start: Today, End: Tomorrow | ✅ Valid |
Start: Yesterday, End: Tomorrow | ❌ Start date in the past |
Start: Tomorrow, End: Today | ❌ End before start |