Easy Shadcn
Components

Date Picker

A flattened date picker that wraps shadcn's Popover and Calendar. Supports single, multiple, and range selection modes via a single mode prop, a configurable date-fns format, and an optional inline-input mode for typing dates by hand.

Single (default trigger, format="PPP")
Multiple (single panel, format="LLL dd, y")
Range (single panel, format="LLL dd, y")
With input — type a date and press Enter

Installation

With the @easy-shadcn namespace configured:

pnpm dlx shadcn@latest add @easy-shadcn/date-picker

Or install via the full URL (zero configuration):

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

The underlying popover, calendar, button, and input primitives (plus the react-day-picker and date-fns dependencies) are installed automatically alongside date-picker.

Usage

Single

import { useState } from "react"
import { DatePicker } from "@/components/easy/date-picker"

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

<DatePicker value={date} onChange={setDate} />

Multiple

Pick any number of independent dates from a single calendar panel. Clicking a selected day deselects it; the popover stays open so multiple picks are quick.

import { useState } from "react"
import { DatePicker } from "@/components/easy/date-picker"

const [dates, setDates] = useState<Date[]>()

<DatePicker mode="multiple" value={dates} onChange={setDates} />

Range

Pick a contiguous fromto range from a single calendar panel. The first click sets from; the second sets to. The popover stays open until the user clicks outside.

import { useState } from "react"
import type { DateRange } from "react-day-picker"
import { DatePicker } from "@/components/easy/date-picker"

const [range, setRange] = useState<DateRange>()

<DatePicker mode="range" value={range} onChange={setRange} />

With input

Enables a text input alongside the calendar trigger. Users can type a date string in the configured format and commit it with Enter or blur. Invalid input silently reverts to the last valid value.

<DatePicker withInput value={date} onChange={setDate} />

Props

PropTypeDefaultDescription
mode"single" | "multiple" | "range""single"Selection mode. Controls the type of value / defaultValue / onChange.
valueDate | Date[] | DateRange-Controlled selected value. Type narrows from mode.
defaultValueDate | Date[] | DateRange-Uncontrolled initial value.
onChange(value: Date | Date[] | DateRange | undefined) => void-Called when the selection changes.
formatstring"PPP"date-fns format token applied to the displayed value and used to parse user input.
localeLocale-date-fns locale forwarded to both the formatter and the Calendar.
placeholderstringmode-dependentTrigger / input placeholder.
disabledbooleanfalseDisables the trigger and (when present) the input.
withInputbooleanfalseRender an <Input /> trigger that accepts manual typing. Single mode only.
numberOfMonthsnumber1Number of months shown side-by-side in the Calendar.
defaultMonthDatederived from the current valueMonth displayed when the calendar first opens.
startMonthDate-Earliest month the user can navigate to. Bounds the year panel.
endMonthDate-Latest month the user can navigate to.
openboolean-Controlled popover open state.
defaultOpenbooleanfalseUncontrolled initial popover open state.
onOpenChange(open: boolean) => void-Called when the popover open state changes.
classNameClassValue-Wrapper className (input mode) or trigger className (button mode).
triggerClassNameClassValue-Trigger element className.
inputClassNameClassValue-<Input /> className. Only used when withInput is true.
iconButtonClassNameClassValue-Calendar-icon button className. Only used when withInput is true.
contentClassNameClassValue-<PopoverContent /> className.
calendarClassNameClassValue-<Calendar /> className.

Notes

  • Default trigger width is w-60 (240px), matching the shadcn official date-picker block. Override with triggerClassName (button mode) or className (input mode) to use a different width.
  • withInput is single-mode only. The TypeScript types reject <DatePicker mode="multiple" withInput /> and <DatePicker mode="range" withInput /> at compile time. Parsing comma-separated dates or "from – to" strings is brittle (separator ambiguity, partial states, locale conflicts) and falls into the 5% bucket — drop down to the underlying Popover + Calendar primitives if you need that.
  • Auto-close behavior. In single mode the popover auto-closes after a date is picked. In multiple and range modes the popover stays open and the user closes it by clicking outside.
  • withInput anchor. When withInput is enabled, the popover is anchored to the surrounding <Input /> wrapper rather than the small calendar-icon button, so the calendar floats directly below the input.
  • Invalid input. When withInput is enabled, blurring the input with an unparseable string silently reverts to the last valid display value. There is no inline error UI by design — wrap the component with your own field state if you need validation messaging.
  • Controlled vs uncontrolled. value === undefined is the controlled-mode detector, matching the convention used by Modal. Passing value={undefined} keeps the component in controlled mode rather than silently switching to uncontrolled.
  • Localization. Pass locale (a date-fns Locale) to localize both the formatted display string (for tokens like "PPP") and the weekday / month labels rendered by the Calendar.

On this page