Components
Date Range Picker Form
A styled form date range picker component built with Shadcn UI, using Zod for schema validation and React Hook Form for form management.
Installation with shadcn/ui
CLI
npx shadcn@latest add https://ved-ui.vercel.app/registry/date-range-picker-form.json
Manual
Install the following dependencies:
npx shadcn@latest add calendar form button sonner popover
Copy and paste the following code into your project.
"use client";
import { z } from "zod";
import { format, addDays } from "date-fns";
import { useForm } from "react-hook-form";
import { CalendarIcon } from "lucide-react";
import { zodResolver } from "@hookform/resolvers/zod";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
const FormSchema = z.object({
dateRange: z
.object({
from: z.date({
required_error: "Start date is required",
}),
to: z.date({
required_error: "End date is required",
}),
})
.refine((data) => data.from <= data.to, {
message: "End date cannot be before start date",
path: ["to"],
}),
});
export function DateRangePickerForm() {
const form = useForm<z.infer<typeof FormSchema>>({
resolver: zodResolver(FormSchema),
defaultValues: {
dateRange: {
from: new Date(),
to: addDays(new Date(), 7),
},
},
});
function onSubmit(data: z.infer<typeof FormSchema>) {
toast.success(
`Date range submitted: ${format(data.dateRange.from, "PPP")} to ${format(
data.dateRange.to,
"PPP"
)}`
);
form.reset();
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="dateRange"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Date Range</FormLabel>
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
variant={"outline"}
className={cn(
"w-[300px] justify-start text-left font-normal",
!field.value && "text-muted-foreground"
)}
>
<CalendarIcon className="mr-2 h-4 w-4" />
{field.value?.from ? (
field.value.to ? (
<>
{format(field.value.from, "LLL dd, y")} -{" "}
{format(field.value.to, "LLL dd, y")}
</>
) : (
format(field.value.from, "LLL dd, y")
)
) : (
<span>Select date range</span>
)}
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
initialFocus
mode="range"
defaultMonth={field.value?.from}
selected={field.value}
onSelect={field.onChange}
numberOfMonths={2}
/>
</PopoverContent>
</Popover>
<FormDescription>
Select the start and end dates for your reservation
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
);
}