Skip to main content

date picker

A date picker component with range and presets.

Philosophy

Date picking is a composition problem, not a component problem. A date picker is just a Calendar inside a Popover triggered by a Button - three components you already have. We document it as a pattern rather than shipping a dedicated component because the "right" date picker varies wildly by use case (single date, range, date-time, with presets).

How It's Built

Loading diagram...

Installation

The Date Picker is built using a composition of the <Popover /> and the <Calendar /> components.

See installation instructions for the Popover and the Calendar components.

Usage

components/example-date-picker.tsx
"use client"
 
import * as React from "react"
import { ChevronDownIcon } from "lucide-react"
 
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import { Label } from "@/components/ui/label"
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"
 
export function DatePickerDemo() {
  const [open, setOpen] = React.useState(false)
  const [date, setDate] = React.useState<Date | undefined>(undefined)
 
  return (
    <div className="flex flex-col gap-3">
      <Label className="px-1" htmlFor="date">
        Date of birth
      </Label>
      <Popover onOpenChange={setOpen} open={open}>
        <PopoverTrigger asChild>
          <Button className="w-48 justify-between font-normal" id="date" variant="outline">
            {date ? date.toLocaleDateString() : "Select date"}
            <ChevronDownIcon aria-hidden="true" />
          </Button>
        </PopoverTrigger>
        <PopoverContent side="top" align="start" className="w-auto p-0">
          <Calendar
            mode="single"
            onSelect={(date) => {
              setDate(date)
              setOpen(false)
            }}
            selected={date}
          />
        </PopoverContent>
      </Popover>
    </div>
  )
}
components/example-date-picker.tsx
"use client"
 
import * as React from "react"
import { ChevronDownIcon } from "lucide-react"
 
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import { Label } from "@/components/ui/label"
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover"
 
export function DatePickerDemo() {
  const [open, setOpen] = React.useState(false)
  const [date, setDate] = React.useState<Date | undefined>(undefined)
 
  return (
    <div className="flex flex-col gap-3">
      <Label className="px-1" htmlFor="date">
        Date of birth
      </Label>
      <Popover onOpenChange={setOpen} open={open}>
        <PopoverTrigger asChild>
          <Button className="w-48 justify-between font-normal" id="date" variant="outline">
            {date ? date.toLocaleDateString() : "Select date"}
            <ChevronDownIcon aria-hidden="true" />
          </Button>
        </PopoverTrigger>
        <PopoverContent side="top" align="start" className="w-auto p-0">
          <Calendar
            mode="single"
            onSelect={(date) => {
              setDate(date)
              setOpen(false)
            }}
            selected={date}
          />
        </PopoverContent>
      </Popover>
    </div>
  )
}

See the @gentleduck/calendar documentation for more information on the headless calendar engine.

Examples

Date of Birth Picker

Picker with Input

Date and Time Picker

Natural Language Picker

This component uses the chrono-node library to parse natural language dates.

Date of Birth Picker (with dropdowns)

Date and Time Picker

Natural Language Picker

Form Integration

RTL Support

RTL is supported through the underlying Calendar and Popover components. Set dir="rtl" on the Calendar or use DirectionProvider at app/root level for global direction.

Motion

Use MotionPopover, MotionPopoverContent, and MotionCalendar for animated date picking. The popover enters/exits with spring animation and the calendar has directional month transitions with staggered day cells.