Skip to content
Components

DatePicker

A field-looking trigger that opens a Calendar in a popover, for picking one date or a range of dates in a form. It takes the same value props as Calendar.

Preview

Props

  • mode
  • value
  • defaultValue
  • disabled
  • minDate
  • maxDate
  • locale
  • weekStartsOn
  • numberOfMonths
  • rangeStartLabel
  • rangeEndLabel
  • placeholder
import { DatePicker } from "@/components/ui/date-picker"

<DatePicker placeholder="Pick a date" className="max-w-md" />

Usage

When to use

  • Picking one date in a form, next to other fields, with the same field look as Input.
  • Limiting the choice to real dates, with disabled days or a min and max date.

When not to use

  • A whole month on the page when the date is the point of the screen. Use Calendar.
  • Entering a date as text, such as a birth date the user knows by heart. Use Input.

Examples

In a form

The trigger has the field look, and the grid opens in a popover.

import { DatePicker } from "@/components/ui/date-picker"

<DatePicker placeholder="When does it start?" />

Booking dates

A range over two months. The popover stays open after check-in and closes after check-out.

import { DatePicker } from "@/components/ui/date-picker"

<DatePicker mode="range" numberOfMonths={2} placeholder="Check-in to check-out" />

Do and don't

Do

  • Use DatePicker in forms, next to Input fields with the same md size.
  • Name it with a Label pointing at its id, and describe it with aria-describedby, like any field.
  • Disable days that can never be picked, such as past days or closed days, over a minDate and maxDate.

Don't

  • Don't use it when the date is the whole screen; put a Calendar on the page instead.
  • Don't put long text in the trigger; it shows one formatted date or one range.
  • Don't use it for dates the user knows by heart, such as a birth date; an Input is faster.

Props

NameTypeValuesDefaultDescription
modeenumsingle | rangesinglesingle picks one Date; range picks a start and an end ({ from, to }) and closes once both are picked.
valuestring--The picked Date, or in range mode the picked range ({ from, to }), when you control it. An explicit undefined clears the selection; omitting value uses internal state. Pair it with onValueChange.
defaultValuestring--The Date, or in range mode the range, picked on first render, when you don't control it.
onValueChangefunction--Called with the picked Date, or undefined when the user unpicks it. In range mode only with a complete range, or undefined when a one-day range is cleared.
disabledboolean-falsetrue disables the trigger; a function receives a Date and disables single days in the Calendar, such as weekends or past dates.
minDatestring--No day before this Date can be picked or navigated to.
maxDatestring--No day after this Date can be picked or navigated to.
localestring--A date-fns Locale object for the trigger text and the Calendar's month and weekday names. The default is enUS.
weekStartsOnenum0 | 1-The first day of the week in the Calendar: 0 Sunday or 1 Monday. Follows the locale when not set.
numberOfMonthsnumber-1How many months the Calendar shows, side by side from sm and stacked below it. Use two for ranges that often cross a month.
rangeStartLabelstring-start of rangeRange mode. Added to the start day's accessible name in the Calendar; translate it with the locale.
rangeEndLabelstring-end of rangeRange mode. Added to the end day's accessible name in the Calendar; translate it with the locale.
placeholderstring-Pick a dateText shown in the trigger while no date is picked. It also names the dialog when there is no aria-label.
modalboolean-falseWhether the open popover blocks interaction with the rest of the page.

Anatomy

PartDescription
rootThe trigger button: the same field look as Input md.
iconA decorative Tabler Calendar icon at the start, 16px, secondary.
labelThe picked date, formatted long; in range mode both ends in the medium format joined by an en dash (one date for a one-day range); or the placeholder in secondary text.
contentThe Popover that holds a Calendar.

Accessibility

Role: button

KeysAction
Space, EnterOn the trigger, opens the popover and focuses the selected day, or today.
EscapeCloses the popover and returns focus to the trigger. In range mode a start without an end is dropped and the value is unchanged.
  • The trigger opens a dialog named by aria-label or the placeholder; inside it, the Calendar grid keeps its own keyboard model.
  • A picked date closes the dialog and focus returns to the trigger.
  • In range mode the popover keeps a draft: it stays open after the start and sends onValueChange only with a complete range (then closes), or with undefined when the user clears a one-day range. A form value is never start-only. Closing with only a start drops it.
  • The trigger accepts id, aria-label and aria-describedby, so a Label and a hint can name and describe it like any field.

Install

npx shadcn add https://werewolf-ui.vercel.app/r/date-picker.json

This also adds styles/werewolf.css, the tokens every component uses, and any other component it needs. Import that file once in your root CSS, after @import "tailwindcss", with a path relative to that CSS file (from app/globals.css it is @import "../styles/werewolf.css").