Skip to content
Drivn
4 min read

Drivn vs shadcn/ui — Calendar Component Compared

Side-by-side comparison of Drivn and shadcn/ui React Calendar components — built-in variants, range mode API, react-day-picker base, and locale setup.

Calendar is the one Drivn component where the runtime-dependency argument does not apply. Both Drivn and shadcn/ui delegate the hard parts — the date grid, arrow-key navigation, ARIA wiring, locale-aware month names — to react-day-picker. Neither library reimplements a day grid, and neither should. What you are actually choosing between is the wrapper each one puts on top of that shared base.

shadcn/ui keeps its wrapper deliberately thin: a classNames map, a mode prop, and every other behavior passed through as raw react-day-picker configuration at each call site. Drivn's Calendar packages the three configurations teams reach for most — the plain month grid, the week-numbered grid, the select-driven caption — behind a single variant prop, and hangs range selection off the same import as Calendar.Range.

The practical difference is how much date-picker plumbing accumulates across a codebase. A birthday field in shadcn means captionLayout, startMonth, endMonth, and caption classNames spelled out again; in Drivn it means variant="dropdown" with fromYear and toYear defaults already spanning forty years. What follows is the API shapes side by side, what each variant actually forwards to react-day-picker, how range mode types differently, and where locale wiring lands. Every snippet is copied from the shipped source, not paraphrased.

Side-by-side comparison

FeatureDrivnshadcn/ui
Underlying libraryreact-day-pickerreact-day-picker
API styleDot notation (Calendar.Range)Named exports + mode prop
Built-in variantsdefault | weekNumbers | dropdownConfigure props each call
Year range shortcutsfromYear / toYear propsManual startMonth / endMonth
Range mode<Calendar.Range /><Calendar mode="range" />
Chevron iconslucide-react (editable)lucide-react (editable)
Locale supportreact-day-picker/localereact-day-picker/locale
Accessibilityreact-day-picker baselinereact-day-picker baseline
LicenseMITMIT
Copy-paste install

API side-by-side

shadcn/ui exports a single Calendar component and changes behavior via a mode prop — mode="single", mode="multiple", or mode="range". Drivn exports Calendar for single-date selection and mounts range mode on the same object as Calendar.Range. One dot access, no mode string, no cast. The Calendar docs cover every prop passed through to react-day-picker.

The usage divergence is small per component but compounds across a form with several pickers. A single import line covers both the single and range variants in Drivn, and TypeScript narrows each to the right selected and onSelect pair — a Date | undefined on the root and a DateRange | undefined on Calendar.Range — without you choosing between union types at the call site.

1// shadcn/ui — named exports + mode prop
2import { Calendar } from '@/components/ui/calendar'
3
4<Calendar
5 mode="single"
6 selected={date}
7 onSelect={setDate}
8/>
9
10<Calendar
11 mode="range"
12 selected={range}
13 onSelect={setRange}
14/>
15
16// Drivn — dot notation, root stays single-mode
17import { Calendar } from '@/components/ui/calendar'
18
19<Calendar selected={date} onSelect={setDate} />
20
21<Calendar.Range selected={range} onSelect={setRange} />

Built-in variants

Three variants ship with the Drivn Calendar, and each one is a preset object merged into the react-day-picker props. default adds nothing. weekNumbers sets showWeekNumber to true, turning on the ISO week column that payroll and sprint-planning UIs tend to require. dropdown sets captionLayout to dropdown and swaps in the dropdownOverrides classNames, so the native month and year selects sit invisibly over a styled label with a small chevron beside it. shadcn/ui has no variant layer — the same three shapes exist, but you assemble each one from loose props every time you render a picker.

The dropdown variant carries one extra convenience. fromYear and toYear are plain numbers that Drivn converts into the startMonth and endMonth Date objects react-day-picker expects, defaulting to a forty-year window centered on the current year. shadcn leaves that conversion to you at every call site. Across a codebase with a signup birthday field, a contract end date, and a reporting range built on the Date Picker, the saved lines are minor individually and obvious in aggregate.

1// Drivn
2<Calendar variant="weekNumbers" selected={date} onSelect={setDate} />
3
4<Calendar variant="dropdown" fromYear={2000} toYear={2030} />
5
6// shadcn/ui equivalent
7<Calendar showWeekNumber mode="single" selected={date} onSelect={setDate} />
8
9<Calendar
10 mode="single"
11 captionLayout="dropdown"
12 startMonth={new Date(2000, 0)}
13 endMonth={new Date(2030, 11)}
14/>

Range mode with Calendar.Range

Date range selection is one of the most common calendar patterns — think booking flows, reporting periods, leave requests. Both libraries wrap react-day-picker's mode="range", but they surface it differently. shadcn reuses the same Calendar with a different mode string; Drivn mounts it as Calendar.Range, which is a pure TypeScript win because the selected prop narrows to DateRange | undefined automatically.

Drivn's range component also applies a rangeActive class set only once the range spans more than one day — the range_start, range_middle, and range_end cells get bg-primary with rounded-left and rounded-right corners. If you only need single-day selection wrapped in a popover with a formatted input, use the Date Picker component, which composes Calendar with Popover and Input.

1'use client'
2import { useState } from 'react'
3import { Calendar, type DateRange } from '@/components/ui/calendar'
4
5export function DateRangeField() {
6 const [range, setRange] = useState<DateRange | undefined>()
7 return <Calendar.Range selected={range} onSelect={setRange} />
8}

Locale and internationalization

Both libraries accept a locale prop from react-day-picker/locale and pass it through to the underlying locale object. Drivn imports it like import { cs } from 'react-day-picker/locale' and passes it to <Calendar locale={cs} />. That applies month names, weekday labels, and first-day-of-week conventions in one line. No extra i18n dependency, no provider, no context — the locale is plain data that travels with the prop.

If you already use a heavier i18n library such as lingui or next-intl in your Next.js app, the Calendar does not read from it. You pass the matching react-day-picker locale for whatever active locale your app has resolved. The installation guide has the full setup — after npx drivn add calendar the component imports are identical between Drivn and shadcn on this axis.

1import { Calendar } from '@/components/ui/calendar'
2import { cs } from 'react-day-picker/locale'
3
4<Calendar locale={cs} selected={date} onSelect={setDate} />
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

Yes — react-day-picker and lucide-react. This is one of the few Drivn components that ships with a runtime UI dependency, because building an accessible date grid from scratch would duplicate work react-day-picker already does well. The styling, variant preset logic, and chevron icons are Drivn's; the keyboard handling, focus trap, and ARIA attributes come from react-day-picker.

Yes. Range selection lives on the same import as single-date selection. You write Calendar.Range instead of Calendar, pass a DateRange object to selected, and get back a typed range on onSelect. No second component to install, no wrapper div, and no mode string — dot notation carries the variation at the call site.

Set fromYear and toYear on the Calendar component. The defaults are today's year minus twenty and plus twenty, which suits birthday pickers and near-future scheduling. Pass explicit numbers for anything tighter or wider — Drivn converts them into the startMonth and endMonth Date objects that react-day-picker expects, so the dropdown caption lists exactly the years you asked for.

Yes, because react-day-picker drives the keyboard model and ARIA attributes on both Drivn and shadcn. Arrow keys navigate days, Page Up and Page Down navigate months, Home and End jump to the start and end of a week, and screen readers announce the currently selected date. Drivn does not override this behavior — the only additions are visual styling and the variant preset shortcuts.