Skip to content
Drivn
5 min read

React Date Picker Component Examples

Drop-in React Date Picker examples: single date, range, year dropdown, custom format, and locale. Built on react-day-picker with one prop-driven import.

Almost every product that touches scheduling needs a date field somewhere — booking windows, billing periods, analytics filters, deadlines, card expiry. The DatePicker in Drivn is the popover-wrapped form of Calendar: a button trigger that opens the month grid, formats whatever the user picks back into the label, and closes itself on outside click or Escape. Reach for it whenever the grid should stay hidden until asked for rather than sitting inline on the page.

The examples below are the patterns that actually recur in shipped interfaces, each one copy-paste ready against the @/components/ui/date-picker path the Drivn CLI installs under. Run npx drivn add date-picker and the snippets compile as written. Because the component source lands in your repository rather than in node_modules, anything the props do not already expose is a local edit — not a theme override or a wrapper component.

Five patterns follow: single-date selection with a controlled Date | undefined, two-click range selection through DatePicker.Range, a year-and-month dropdown for values far from today, custom trigger labels via formatDate, and locale objects that shift the weekday headers, month names, and first day of the week together. For the inline grid with no trigger at all, the Calendar examples page covers that case instead.

Single-date selection

The default DatePicker renders a button trigger with a CalendarDays icon and the placeholder text. Click the button and a calendar grid opens below. Pass selected as Date | undefined and onSelect as the setter — react-day-picker handles day clicks via the wrapped Calendar, and the popover dismisses automatically once a date is picked.

Because the DatePicker source lives in your repo after install, swapping the trigger styling or adding an extra aria-label is a local edit. The minimum viable integration is below: a controlled useState<Date | undefined> bound to the component, no wrapper div needed.

1import { useState } from "react"
2import { DatePicker } from "@/components/ui/date-picker"
3
4export default function Page() {
5 const [date, setDate] = useState<Date | undefined>()
6
7 return (
8 <DatePicker
9 selected={date}
10 onSelect={setDate}
11 />
12 )
13}

Range selection with DatePicker.Range

DatePicker.Range is mounted on the same root via dot notation. The selected prop narrows to DateRange | undefined, where DateRange = { from: Date; to?: Date }, re-exported from react-day-picker. The first click sets from, the second click sets to, and the trigger label formats as Apr 1 – Apr 7. The popover stays open between clicks and only closes when the range completes, so the user does not have to reopen the trigger to set the second date.

This pattern fits booking flows, leave requests, reporting period filters, and any UI where two related dates need to be picked together. For the inline (non-popover) version of range selection, use Calendar.Range directly.

1import { useState } from "react"
2import {
3 DatePicker,
4 type DateRange,
5} from "@/components/ui/date-picker"
6
7export default function Page() {
8 const [range, setRange] = useState<DateRange | undefined>()
9
10 return (
11 <DatePicker.Range
12 selected={range}
13 onSelect={setRange}
14 />
15 )
16}

Year and month dropdown variant

Paginating month-by-month is fine for next Tuesday and miserable for a 1987 birthday. Pass variant="dropdown" and the month-and-year caption becomes a pair of <select> elements the user can jump through directly. The default window is today's year plus and minus twenty; fromYear and toYear widen it — fromYear={1900} for date of birth, toYear={2050} for card expiry, or any bounded historical range for a reporting filter.

Both props forward straight through to the wrapped Calendar, which converts them into the startMonth and endMonth Date objects react-day-picker expects and swaps in the dropdown caption layout. There is no date-fns helper to import and no caption template to write — one prop changes the interaction model. Note that variant, fromYear, and toYear are single-date props: DatePicker.Range takes the base props only, so a range picker keeps the paging caption.

1<DatePicker
2 variant="dropdown"
3 selected={date}
4 onSelect={setDate}
5/>

Custom date formatting

By default the trigger label uses toLocaleDateString with month: "short", day: "numeric", year: "numeric"Apr 27, 2026. Pass a formatDate function to override how the selected date renders. The function takes a Date and returns a string; Drivn shows whatever you return inside the trigger button.

A common case is European day-month-year ordering or a tighter MM/DD/YYYY. Build the formatter inline or import a shared one from your i18n module — the prop accepts any (date: Date) => string. The same function applies whether you pass a single date or compose DatePicker.Range, where the formatter runs against both from and to separately.

1import { useState } from "react"
2import { DatePicker } from "@/components/ui/date-picker"
3
4export default function Page() {
5 const [date, setDate] = useState<Date | undefined>()
6
7 return (
8 <DatePicker
9 selected={date}
10 onSelect={setDate}
11 formatDate={(d) =>
12 d.toLocaleDateString("en-GB", {
13 day: "2-digit",
14 month: "2-digit",
15 year: "numeric",
16 })
17 }
18 />
19 )
20}

Locale support

Pass a locale from react-day-picker/locale and the trigger label, weekday headers, month names, and first-day-of-week all update together. A Czech locale (cs) shifts the grid to start on Monday and renders month names as leden / únor / březen. No provider, no separate i18n setup — the locale is plain data passed by prop.

Dozens of locales ship pre-built in react-day-picker/locale. Pick the one matching your app's active locale and pass it in. If your translation layer already resolves a locale string, wire it through React context and the DatePicker reads from there. For tokens that affect the calendar appearance beyond what locale objects cover, see the theming docs.

1import { useState } from "react"
2import { DatePicker } from "@/components/ui/date-picker"
3import { cs } from "react-day-picker/locale"
4
5export default function Page() {
6 const [date, setDate] = useState<Date | undefined>()
7
8 return (
9 <DatePicker
10 locale={cs}
11 selected={date}
12 onSelect={setDate}
13 />
14 )
15}
Get started

Install Drivn in one command

Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.

npx drivn@latest create

Requires Node 18+. Works with npm, pnpm, and yarn.

Enjoying Drivn?
Star the repo on GitHub to follow new component releases.
Star →

Frequently asked questions

Calendar renders the month grid inline. DatePicker wraps Calendar in a trigger button plus a controlled popover, handling outside-click and Escape dismissal for you. Use Calendar when the grid is always visible — sidebar, card, booking widget. Use DatePicker when the grid should open from a button, the way most form inputs do.

Yes — DatePicker.Range is mounted on the same import via dot notation. Pass a DateRange | undefined to selected and a (range) => void to onSelect. The popover stays open between the two clicks and dismisses once both from and to are set. No additional component to install or import.

No — popover behavior is built in. The component manages its own open state, listens for outside clicks via a document mousedown listener, and dismisses on Escape via a keyboard listener. Open state, dismiss handlers, and the closing animation live inside date-picker.tsx. You do not need to install or compose a separate Popover primitive.

Pass defaultMonth as a Date. The calendar opens to that month but leaves selected undefined, so no day is highlighted. This is useful for vacation pickers that should open on next month, quarterly filters that should open on the start of Q1, or any case where you want to nudge the user toward a period without committing to a date yet.

The DatePicker file starts with "use client" because it manages state with useState and listens for events. You can import it from a Server Component, but it renders on the client. Next.js draws the client boundary correctly based on the use client directive at the top of the file — no manual configuration needed in your layout or page.