Calendar

Accessible date and range selection with React DayPicker and Migoy styling.

Preview

November 2026

November 12, 2026

Installation

pnpm dlx shadcn@latest add http://127.0.0.1:3017/r/calendar.json

Installs Calendar, Migoy Button, React DayPicker, date-fns, and Lucide icons. Uses your existing theme and cn utility. The endpoint is local; see the registry guide for reviewed updates.

The linked shadcn Base UI Calendar is built on React DayPicker. It uses DayPicker's selection API, with no Base UI trigger composition required.

Usage

'use client';

import * as React from 'react';
import { Calendar } from '@/components/ui/calendar';

export function DateSelection() {
  const [date, setDate] = React.useState<Date | undefined>();
  return (
    <Calendar
      mode="single"
      selected={date}
      onSelect={setDate}
      className="rounded-lg border"
      aria-label="Choose a date"
    />
  );
}

Use required to prevent clearing the selection. Use mode="multiple" with a Date[] selection to choose independent dates. Selection is controlled through selected and onSelect; omitting a selection mode displays a calendar without selectable dates.

Composition

Calendar wraps React DayPicker and assembles its navigation, month grids, and day buttons internally:

Calendar
├── Month navigation (internal)
└── Month grid (one per displayed month, internal)
    └── CalendarDayButton (one per selectable day, internal)

Render Calendar directly; do not manually nest day buttons inside it. Configure selection with mode, selected, and onSelect. Use the components, classNames, and formatters props for supported customization. CalendarDayButton is exported for custom DayPicker day-button implementations, where DayPicker supplies its day and modifiers props.

To anchor a calendar to a button, use the Date Picker composition with Popover.

Date range

November 2026
December 2026

November 12, 2026 – November 17, 2026

import type { DateRange } from 'react-day-picker';

const [range, setRange] = React.useState<DateRange | undefined>();

<Calendar
  mode="range"
  selected={range}
  onSelect={setRange}
  numberOfMonths={2}
  className="rounded-lg border"
/>

Months stack on narrow screens. min and max constrain the number of nights. Use excludeDisabled with disabled dates when ranges must not cross unavailable days.

November 2026

Choose a weekday; weekends are unavailable.

<Calendar
  mode="single"
  captionLayout="dropdown"
  startMonth={new Date(2026, 0)}
  endMonth={new Date(2027, 11)}
  disabled={{ dayOfWeek: [0, 6] }}
  selected={date}
  onSelect={setDate}
/>

Set explicit navigation bounds for dropdowns. Disabled dates remain visible but cannot be selected. Navigation bounds and selectable-date bounds are separate: use disabled to restrict selection as well.

Customization

PropDefault / purpose
showOutsideDaystrue
captionLayoutlabel; supports dropdown layouts
buttonVariantghost navigation buttons
localeDayPicker locale, including translated labels
weekStartsOnLocale default; 1 for Monday
showWeekNumberOptional week-number column
classNames, components, formattersOverride DayPicker slots
timeZoneExplicit IANA zone when required

CalendarDayButton is also exported for custom day content. Day cells use the shared 32px control height and 4px radius fallbacks. For a larger touch layout, set className="[--cell-size:44px]". Selected dates use primary tokens, ranges use muted tokens, and today has a neutral highlight. The component adds no default shadow.

Demo calendars use November 2026 and a fixed today marker for reproducible previews. Product calendars use the actual current date unless today is supplied. Construct date-only values with new Date(year, monthIndex, day) to avoid parsing UTC date strings into the previous local day. For explicit timeZone usage, use timezone-aware date values consistently as described by DayPicker.

Accessibility

  • Tab enters the calendar; arrow keys move between days.
  • Enter or Space selects the focused date. Page Up and Page Down navigate months.
  • Selected, disabled, and today states retain DayPicker's accessible labels.
  • Give the calendar a clear accessible name and show the selected date in accompanying text.
  • When placing a calendar inside a Popover, provide a popover title and manage dismissal after selection.

Based on shadcn Calendar and React DayPicker.

On this page