Date Range Picker

Popover calendar for selecting a start and end date.

Report a bug

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Installation

pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/date-range-picker.json

Storybook

Explore all variants, controls, and accessibility checks in the interactive Storybook playground.

View in Storybook

2 stories available:

Code

"use client"; import * as React from "react"; import { CalendarIcon } from "lucide-react"; import type { DateRange } from "react-day-picker"; import { cn } from "../../lib/utils"; import { Button } from "../button/button"; import { Calendar } from "../calendar"; import { Popover, PopoverContent, PopoverTrigger } from "../popover"; const rangeFormatter = new Intl.DateTimeFormat("en-US", { day: "numeric", month: "short", year: "numeric", }); function formatRange(range: DateRange | undefined): string | undefined { if (!range?.from) { return undefined; } if (!range.to) { return rangeFormatter.format(range.from); } return `${rangeFormatter.format(range.from)}${rangeFormatter.format(range.to)}`; } /** Popover date-range picker built on the range calendar. */ export type DateRangePickerProps = { buttonClassName?: string; className?: string; defaultValue?: DateRange; numberOfMonths?: number; onValueChange?: (range?: DateRange) => void; placeholder?: string; value?: DateRange; }; const DateRangePicker = ({ buttonClassName, className, defaultValue, numberOfMonths = 2, onValueChange, placeholder = "Pick a date range", ref, value, }: DateRangePickerProps & { ref?: React.Ref<HTMLButtonElement> }) => { const [internalValue, setInternalValue] = React.useState< DateRange | undefined >(defaultValue); const selected = value ?? internalValue; const label = formatRange(selected); const handleSelect = (range: DateRange | undefined) => { if (value === undefined) { setInternalValue(range); } onValueChange?.(range); }; return ( <Popover> <PopoverTrigger asChild> <Button className={cn( "w-full justify-start text-left font-normal", !label && "text-muted-foreground", buttonClassName, )} ref={ref} variant="outline" > <CalendarIcon className="mr-2 size-4" /> {label ?? placeholder} </Button> </PopoverTrigger> <PopoverContent align="start" className={cn("w-auto p-0", className)}> <Calendar mode="range" numberOfMonths={numberOfMonths} onSelect={handleSelect} selected={selected} /> </PopoverContent> </Popover> ); }; DateRangePicker.displayName = "DateRangePicker"; export { DateRangePicker };

Dependencies

  • @vllnt/ui@^0.2.1