Components
A date field component that lets users browse months and select single dates, multiple dates or ranges. Built on React DayPicker.
Playground
mode to pick the selection behavior. Selection is uncontrolled by default — pass selected and onSelect to control it from your own state, as in the Date picker example below.import { Calendar } from "@workspace/ui/components/calendar"
<Calendar mode="single" className="rounded-lg border" />mode="range" selects a start and end date; the days in between get the muted range styling. numberOfMonths lays out extra months side by side, which pairs naturally with range selection.<Calendar
mode="range"
numberOfMonths={2}
className="rounded-lg border"
/>captionLayout="dropdown" replaces the caption label with native month and year selects — handy for far-away dates like birthdays. dropdown-months and dropdown-years switch only one side. Bound the year list with startMonth and endMonth.<Calendar
mode="single"
captionLayout="dropdown"
startMonth={new Date(1990, 0)}
endMonth={new Date(2030, 11)}
className="rounded-lg border"
/>disabled prop accepts a matcher or an array of matchers: specific dates, a { before, after } window, or dayOfWeek indices. Disabled days keep their slot in the grid but cannot be focused or selected — here weekends are off-limits.<Calendar
mode="single"
disabled={{ dayOfWeek: [0, 6] }}
className="rounded-lg border"
/>showWeekNumber prepends an ISO week-number column rendered in text-muted-foreground. showOutsideDays (on by default) fills the leading and trailing cells with the neighboring months.<Calendar mode="single" showWeekNumber className="rounded-lg border" />
--cell-size CSS variable (default --spacing(8)), and cell corners by --cell-radius. Override them with arbitrary-property classes to scale the whole calendar without touching individual parts.<Calendar mode="single" className="rounded-lg border [--cell-size:--spacing(10)]" />
onSelect stores the date and closes the popover. Strip the popover padding with w-auto p-0 — the calendar already carries its own.const [open, setOpen] = React.useState(false)
const [date, setDate] = React.useState<Date | undefined>(undefined)
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button variant="outline" className="w-56 justify-start font-normal">
<CalendarBlankIcon className="text-muted-foreground" />
{date
? date.toLocaleDateString("en-US", { dateStyle: "long" })
: <span className="text-muted-foreground">Pick a date</span>}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
mode="single"
selected={date}
captionLayout="dropdown"
onSelect={(selected) => {
setDate(selected)
setOpen(false)
}}
/>
</PopoverContent>
</Popover>react-day-picker/locale together with dir="rtl". The month grid, range styling and nav chevrons all mirror via logical properties — the previous / next buttons swap direction without extra classes.import { ar } from "react-day-picker/locale"
<Calendar mode="single" locale={ar} dir="rtl" className="rounded-lg border" />autoFocus to move focus into the grid when the calendar appears inside a popover.<PopoverContent className="w-auto p-0" align="start"> <Calendar mode="single" autoFocus /> </PopoverContent>
components.DayButton overrides.| Component | Prop | Default |
|---|---|---|
| Calendar | mode?: "single" | "multiple" | "range" | — |
| Calendar | selected?, onSelect?: controlled selection for the active mode | — |
| Calendar | captionLayout?: "label" | "dropdown" | "dropdown-months" | "dropdown-years" | "label" |
| Calendar | numberOfMonths?: number | 1 |
| Calendar | showOutsideDays?: boolean | true |
| Calendar | showWeekNumber?: boolean | false |
| Calendar | disabled?: Matcher | Matcher[] | — |
| Calendar | buttonVariant?: Button variant for the nav buttons | "ghost" |
| Calendar | locale?: Locale, dir?: "ltr" | "rtl" | — |
<Calendar data-slot="calendar" /> <CalendarDayButton data-day data-selected-single data-range-start data-range-middle data-range-end />
Tokens used
14 design tokens consumed by the Calendar component.
--background
Background
--primary
Primary
--primary-foreground
Primary Foreground
--muted
Muted
--foreground
Foreground
--muted-foreground
Muted Foreground
--accent
Accent
--accent-foreground
Accent Foreground
--popover
Popover
--ring
Ring
--radius-md
Radius Medium (via --cell-radius)
--spacing
Spacing unit (4px, via --cell-size)
--text-sm
Text Small (14px)
--font-weight-medium
Font weight Medium (500)