Date Picker

A button that opens a calendar in a popover to choose a date or a range.

'use client'

import * as React from 'react'
import { DatePicker } from '@/components/ui/date-picker'
import { Label } from '@/components/ui/label'

export default function DatePickerDemo() {
  const [date, setDate] = React.useState<Date | undefined>()

  return (
    <div className="grid gap-1.5">
      <Label htmlFor="date-picker-demo">Appointment date</Label>
      <DatePicker id="date-picker-demo" value={date} onValueChange={setDate} />
    </div>
  )
}

Built on Base UI

Installation

pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/date-picker.json

Needs a React + Tailwind project set up with shadcn. Copies the component source straight into your project, so you can edit it.

Date Picker imports cn() from lib/utils.ts — add it too if you don't have it yet:

import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

Built from Calendar, Popover and Button. The CLI installs them for you; if you copy manually, add calendar.tsx, popover.tsx and button.tsx to components/ui/ too.

Usage

import { DatePicker, DateRangePicker } from '@/components/ui/date-picker'
import { Label } from '@/components/ui/label'

const [date, setDate] = useState<Date | undefined>()

<Label htmlFor="when">Appointment date</Label>
<DatePicker id="when" value={date} onValueChange={setDate} />

// A range
<DateRangePicker value={range} onValueChange={setRange} />

// Options for the calendar inside
<DatePicker calendarProps={{ disabled: { before: new Date() } }} />

Examples

Date range

'use client'

import * as React from 'react'
import type { DateRange } from 'react-day-picker'
import { DateRangePicker } from '@/components/ui/date-picker'
import { Label } from '@/components/ui/label'

export default function DatePickerRange() {
  const [range, setRange] = React.useState<DateRange | undefined>()

  return (
    <div className="grid gap-1.5">
      <Label htmlFor="date-picker-range">Stay</Label>
      <DateRangePicker id="date-picker-range" value={range} onValueChange={setRange} />
    </div>
  )
}

API Reference

NameTypeDefaultDescription
value / onValueChangeDate | undefined / (date) => void—The picked date (controlled). For DateRangePicker the value is { from, to }.
defaultValueDate | DateRange—The initially picked date or range (uncontrolled).
placeholderstring'Pick a date' / 'Pick a date range'Text shown on the button while nothing is picked.
formatDate(date: Date) => stringen-US, mediumTurns a date into the button text, e.g. (d) => d.toLocaleDateString("de-DE").
calendarPropsCalendarProps—Passed to the Calendar: disabled, locale, weekStartsOn, numberOfMonths, captionLayout, …
disabledbooleanfalseDisables the button.
id / aria-label / classNamestring—Set on the trigger button, so a <Label htmlFor> can name it.
Closing——The popover closes when a date is picked (for a range, when the start and end days are). Escape closes it and returns focus to the button.
Keyboard——Opening the popover moves focus to the selected day (or today), so the arrow keys move straight away; Enter picks.