Next.js Calendar — Date Picker for App Router
Add a Next.js Calendar with single-date and range selection. Drivn ships a single-file react-day-picker wrapper that drops into any App Router client island.
Date pickers are one of the trickier primitives to place in a Next.js App Router project. Selection state lives on the client, but the page around the calendar — the form, the layout, the surrounding copy — can stay on the server. You want a component that opens a client boundary exactly where the calendar sits and nowhere else, plus a file small enough to read when you need to adjust a class.
Drivn's Calendar is a thin wrapper over react-day-picker. After install it lives in src/components/ui/calendar.tsx, marks itself 'use client', and carries no UI dependencies beyond React, react-day-picker, and lucide-react for the navigation chevrons. Single-date selection, range selection via Calendar.Range, week numbers, dropdown month and year navigation, and locale support are all driven through props — there is no second package to wire up and no headless context to assemble.
This guide walks through installing Drivn in a Next.js 16 project, rendering the Calendar inside a server-component page as a controlled client island, wiring selected and onSelect state, switching to range mode, and localizing the month grid. Every snippet is drawn from the component's actual API. For the full reference see the Calendar docs; for the shadcn/ui comparison see Drivn vs shadcn/ui Calendar.
Install in a Next.js 16 project
Drivn installs through a tiny CLI that writes the component source file directly into your repository — there is no runtime npm package and no version lock to upgrade. Open a terminal in the root of your Next.js 16 project and run npx drivn add calendar. The CLI prompts once for your install directory (defaulting to src/components/ui/) and copies calendar.tsx, then adds its two dependencies — react-day-picker for the grid logic and lucide-react for the chevron icons — to your package.json if they are missing. The CLI reference documents every flag, including how to target a custom path or install several components at once. After install you own the file; future Drivn releases will not overwrite it, and you can edit the internals without forking a package. Commit the change so you have a clean baseline before customizing.
1 # from the root of your Next.js 16 project 2 npx drivn add calendar 3 4 # install a related form primitive at the same time if needed 5 npx drivn add input
Render as a controlled client island
An App Router page is a server component by default, so it cannot call useState. Drivn's Calendar is marked 'use client' at the top of its source file because it relies on react-day-picker, which tracks selection on the client. The clean pattern is to keep the calendar and its state in a small client component, then render that island inside an otherwise server-rendered page. Import the component from @/components/ui/calendar, hold the selected date in useState, and bind selected and onSelect. No dynamic() import and no SSR-disable flag are needed — Next.js inserts the client boundary automatically when it crosses the 'use client' directive. The installation guide covers project bootstrapping; the Calendar docs list every prop.
1 'use client' 2 import { useState } from 'react' 3 import { Calendar } from '@/components/ui/calendar' 4 5 export function BookingDate() { 6 const [date, setDate] = useState<Date | undefined>() 7 return ( 8 <Calendar 9 selected={date} 10 onSelect={setDate} 11 /> 12 ) 13 }
Switch to range selection
For check-in/check-out flows, report windows, or any from–to picker, use the Calendar.Range sub-component. It is exposed through the same dot-notation API — Calendar.Range is attached to the root via Object.assign in the source, so one import gives you both modes. Range mode renders react-day-picker with mode="range" and a selected value shaped as { from, to }. The component applies rounded start and end caps and fills the middle days with the accent token once a full range is chosen, so the visual feedback matches the user's intent. Import the DateRange type alongside the component for a fully typed state value. See the date picker docs for a popover-wrapped variant built on the same calendar.
1 'use client' 2 import { useState } from 'react' 3 import { Calendar, type DateRange } from '@/components/ui/calendar' 4 5 export function StayRange() { 6 const [range, setRange] = useState<DateRange | undefined>() 7 return ( 8 <Calendar.Range 9 selected={range} 10 onSelect={setRange} 11 /> 12 ) 13 }
Localize the month grid
Drivn's Calendar passes through react-day-picker's locale prop, so localizing the month names, weekday labels, and first day of the week is a one-line change. Import the locale object you need from react-day-picker/locale and pass it to the component — the grid re-labels itself and respects locale-specific week start (Monday in most of Europe, Sunday in the US). Because the locale data comes from react-day-picker rather than a Drivn-specific table, every locale the library supports works without extra wiring. To customize the surface colors instead, edit the styles object at the top of calendar.tsx; its root and class-name keys read from your Tailwind tokens, so a theme change in globals re-themes every calendar instance at once.
1 // styles.root from src/components/ui/calendar.tsx 2 const styles = { 3 root: 'p-3 bg-card border border-border rounded-[10px] text-sm', 4 // ...classNames, dropdownOverrides, rangeActive 5 }
Install Drivn in one command
Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.
npx drivn@latest createRequires Node 18+. Works with npm, pnpm, and yarn.
Frequently asked questions
The Calendar itself is a client component — it is marked 'use client' because it wraps react-day-picker, which manages selection state with hooks. Your surrounding page and layout can still render on the server. The usual pattern is a small client component that holds the calendar plus its useState, rendered as an island inside an otherwise server-rendered route. Next.js inserts the client boundary automatically at the import.
Use the Calendar.Range sub-component exposed through the same import. It renders react-day-picker in mode="range" and expects a selected value shaped as { from, to }. Import the DateRange type alongside the component to type your state. Drivn applies rounded start and end caps and fills the middle days with the accent token once both endpoints are chosen.
Yes. The Calendar forwards a locale prop to react-day-picker. Import a locale object from react-day-picker/locale — such as cs for Czech or de for German — and pass it to the component. The month names, weekday headers, and week-start day all update to match. No Drivn-specific localization table is involved; any locale the underlying library ships works out of the box.
Not for an inline calendar — render it directly on the page. If you want a click-to-open input that reveals the calendar in a floating panel, Drivn ships a separate Date Picker component that composes the Calendar inside a Popover. Use the inline Calendar for booking grids and scheduling views, and the Date Picker for compact form fields where space is limited.

