Calendar
A date field component that allows users to enter and edit date.
Powered by
Installation
npx shadcn@latest add @redpanda/calendarpnpm dlx shadcn@latest add @redpanda/calendaryarn dlx shadcn@latest add @redpanda/calendarbunx shadcn@latest add @redpanda/calendarnubx shadcn@latest add @redpanda/calendaraube dlx shadcn@latest add @redpanda/calendarUsage
The Calendar component is built on react-day-picker and supports various modes and configurations for different date selection needs:
import { Calendar } from '@/components/redpanda-ui/calendar';import { useState } from 'react';
// Single date selectionconst [date, setDate] = useState<Date | undefined>(new Date());
return <Calendar mode="single" selected={date} onSelect={setDate} variant="outlined" />;
// Date range selectionconst [dateRange, setDateRange] = useState<DateRange | undefined>();
return <Calendar mode="range" selected={dateRange} onSelect={setDateRange} numberOfMonths={2} variant="outlined" />;
// Multiple date selectionconst [dates, setDates] = useState<Date[]>([]);
return <Calendar mode="multiple" selected={dates} onSelect={setDates} variant="outlined" />;
// With disabled datesconst isDateDisabled = (date: Date) => { return date < new Date() || date.getDay() === 0 || date.getDay() === 6;};
return <Calendar mode="single" selected={date} onSelect={setDate} disabled={isDateDisabled} variant="outlined" />;Surface variants
Use variant for the calendar surface rather than overriding its border, padding, or background.
| Variant | Surface |
|---|---|
default |
Padded background without a frame |
outlined |
Rounded border and default padding |
elevated |
Outlined surface with a small shadow |
embedded |
Transparent surface without padding, for a padded card or popup |
Date selection, keyboard navigation, and day components work the same in every variant.
Date-action appearance and composition
Calendar owns the selected, range, today, focus, and disabled date-action treatments. Date actions are native
buttons using DayPicker’s type, tabIndex, ARIA attributes, and event handlers, not the general Button appearance
API. buttonVariant styles only the month navigation controls.
Use booked for the supported struck-through booking treatment. It accepts the same date matchers as DayPicker’s
disabled prop. Booking appearance does not change availability: also pass disabled when those dates cannot be selected.
const bookedDates = [new Date(2026, 9, 26), new Date(2026, 9, 27)];
<Calendar booked={bookedDates} disabled={bookedDates} mode="single" onSelect={setDate} selected={date} />;The public classNames, styles, modifiersClassNames, and modifiersStyles paint maps have been removed.
Legacy map props also fail with an explicit migration error at runtime, including when forwarded through a spread.
Use the finite surface variants and booked treatment instead. Root className and root style remain the
existing layout/cell-sizing contract; they are not replacements for retired day paint maps.
Custom day content remains supported through components.DayButton. Forward every received native prop and the
original day and modifiers to CalendarDayButton; this preserves DayPicker’s focus, keyboard, ARIA, and
availability protocol. Incoming day className/style belong to that framework protocol, not an additional public
Button styling API. Refs are forwarded without replacing DayPicker’s internal focus ref, including React callback cleanup.
import { CalendarDayButton } from '@/components/redpanda-ui/calendar';import type { ComponentProps } from 'react';
function PricedDay({ children, day, modifiers, ...props }: ComponentProps<typeof CalendarDayButton>) { return ( <CalendarDayButton day={day} modifiers={modifiers} {...props}> {children} {modifiers['outside'] !== true && <span>$100</span>} </CalendarDayButton> );}Do not set disabled from modifiers.disabled inside a custom day renderer. DayPicker intentionally keeps a
focused disabled day natively focusable with aria-disabled while preventing selection. Forward its supplied
attributes instead. Day actions default to type="button", so ordinary selection does not submit an enclosing form.
When to use
Use this decision tree to determine when to use the Calendar component and which configuration is most appropriate:
Mode Guidelines
- Single mode: Birthdate selection, appointment dates, event dates
- Range mode: Hotel bookings, vacation planning, reporting periods
- Multiple mode: Available dates, blackout dates, recurring events
Calendar vs DatePicker
- Use Calendar when: You have space for inline display, users need to see surrounding dates context, visual date exploration is important
- Use DatePicker when: Space is limited, part of a form, simple date input without exploration needs
Anatomy
The Calendar component is built on react-day-picker with custom styling and components:
Calendar Component Structure:┌─────────────────────────────────────────┐│ Calendar Root Container ││ ┌─────────────────────────────────────┐ ││ │ Navigation Bar │ ││ │ [◀ Prev] [Month Year] [Next ▶] │ ││ │ │ ││ │ - Dropdown: month/year selection │ ││ │ - Buttons: navigation controls │ ││ └─────────────────────────────────────┘ ││ ┌─────────────────────────────────────┐ ││ │ Weekday Headers │ ││ │ [Mon] [Tue] [Wed] [Thu] [Fri] [Sat] │ ││ └─────────────────────────────────────┘ ││ ┌─────────────────────────────────────┐ ││ │ Date Grid │ ││ │ [30] [31] [ 1] [ 2] [ 3] [ 4] [ 5] │ ││ │ [ 6] [ 7] [ 8] [ 9] [10] [11] [12] │ ││ │ [13] [14] [15] [16] [17] [18] [19] │ ││ │ [20] [21] [22] [23] [24] [25] [26] │ ││ │ [27] [28] [29] [30] [31] [ 1] [ 2] │ ││ │ │ ││ │ - Day buttons: individual dates │ ││ │ - States: selected, today, disabled │ ││ │ - Range: start, middle, end │ ││ └─────────────────────────────────────┘ ││ ││ Multi-month layout (when enabled): ││ [Month 1] [Month 2] [Month 3] │└─────────────────────────────────────────┘Component Composition
- DayPicker Root: Base component from react-day-picker with custom theming
- Navigation: Custom chevron icons and dropdown selectors
- Day Buttons: Native date actions with owned selection states and DayPicker’s keyboard/focus protocol
- Weekday Headers: Localized day name labels
- Date Grid: Responsive grid layout with proper spacing
- Range Selection: Visual indicators for start, middle, and end dates
- Accessibility: Full keyboard navigation and screen reader support
Examples
Default
Popover DatePicker
Booked
Custom Days
Disabled Days
Disabled Weekends
Event Slots
Form
Date-fns
Localized
Month Day Dropdown
Multi Month Multi Select
Multi Month Range
Presets
Range Minimum and Maximum Days
Range Minimum Days
Single Month Range
Size
Start End Month
Time Picker
Time Picker Inline
Time Presets
This example only selects a local date and time. Its footer describes that selection; it does not book a meeting or provide an inert review action. Time actions use the standard Button shadow and selected treatment.
Today
Week Numbers
Appointment Slots
Per-Day Pricing
Props
Date Picker
You can use the <Calendar> component to build a date picker. See the Date Picker page for more information.
Credits
- We use react-day-picker for the calendar component.
- We take our inspiration from Shadcn UI for the calendar style.
- We took many components from Shadcn UI Blocks for the calendar component.