Calendar
A month grid for picking a single date or a date range.
@zenoxai/ui/components/calendar Markdownfunction CalendarDemo() {
const [date, setDate] = React.useState<Date | undefined>(
new Date(2026, 9, 14)
)
return (
<Calendar
mode="single"
selected={date}
onSelect={setDate}
defaultMonth={date}
className="rounded-lg border border-border"
/>
)
}Usage
import * as React from "react"
import { Calendar } from "@zenoxai/ui/components/calendar"
export function ScanDate() {
const [date, setDate] = React.useState<Date | undefined>()
return <Calendar mode="single" selected={date} onSelect={setDate} />
}
Calendar is React DayPicker styled with the Zenox tokens. It accepts
every DayPicker prop: mode, selected, onSelect, disabled, numberOfMonths, locale
and the rest. The wrapper adds buttonVariant, the Button variant of the
previous and next month buttons (ghost by default).
The selected day, and the start and end of a range, are filled with the primary color and keep
it on hover. The days inside a range sit on the soft selection band (primary-soft), hover is
the plain surface-muted step, and today is marked by its text (primary, semibold) rather
than a fill, so the three never look alike.
Render the calendar inline when picking a date is the main task of the view, such as scheduling a scan. In a form, open it from a button in a Popover, so it takes space only while the user picks. For a date the user knows by heart, like a birth date, a typed Input is faster.
Examples
Date range
mode="range" selects a start and an end date. selected is a { from, to } object; to is
undefined until the user picks the second date. Show two months with numberOfMonths={2} so
most ranges fit without paging.
function CalendarRange() {
const [range, setRange] = React.useState<
{ from: Date | undefined; to?: Date } | undefined
>({ from: new Date(2026, 9, 6), to: new Date(2026, 9, 19) })
return (
<Calendar
mode="range"
selected={range}
onSelect={setRange}
defaultMonth={range?.from}
numberOfMonths={2}
className="rounded-lg border border-border"
/>
)
}Disabled days
disabled takes one or more matchers: a date, a { before } or { after } bound, a
{ from, to } range, a { dayOfWeek } list or a function. Here a scan can only be scheduled on
a weekday from October 12 on.
function CalendarDisabledDays() {
const [date, setDate] = React.useState<Date | undefined>()
return (
<Calendar
mode="single"
selected={date}
onSelect={setDate}
defaultMonth={new Date(2026, 9, 1)}
disabled={[{ before: new Date(2026, 9, 12) }, { dayOfWeek: [0, 6] }]}
className="rounded-lg border border-border"
/>
)
}Month and year dropdowns
captionLayout="dropdown" replaces the caption with month and year selects, for dates far
from today. Bound them with startMonth and endMonth.
function CalendarDropdowns() {
const [date, setDate] = React.useState<Date | undefined>(new Date(2026, 2, 3))
return (
<Calendar
mode="single"
selected={date}
onSelect={setDate}
defaultMonth={date}
captionLayout="dropdown"
startMonth={new Date(2020, 0)}
endMonth={new Date(2026, 11)}
className="rounded-lg border border-border"
/>
)
}Date picker
A button that shows the chosen date and opens the calendar in a popover. Control the popover
with open and onOpenChange to close it once a date is picked.
function CalendarDatePicker() {
const [open, setOpen] = React.useState(false)
const [date, setDate] = React.useState<Date | undefined>()
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger
render={<Button variant="outline" className="w-52 justify-start" />}
>
<CalendarIcon data-icon="inline-start" />
{date
? date.toLocaleDateString("en-US", { dateStyle: "medium" })
: "Pick a report date"}
</PopoverTrigger>
<PopoverContent align="start" className="w-auto p-0">
<Calendar
mode="single"
selected={date}
onSelect={(next) => {
setDate(next)
setOpen(false)
}}
defaultMonth={date ?? new Date(2026, 9, 1)}
/>
</PopoverContent>
</Popover>
)
}Accessibility
- The month is a grid. Arrow keys move between days, Page Up and Page Down change the month (with Shift, the year), Home and End jump to the start and end of the week, and Enter or Space selects the focused day.
- Every day button has a full date as its label (“Wednesday, October 14th, 2026”), and the
previous and next buttons are labelled. Pass
locale(fromreact-day-picker/locale) to translate the labels together with the month and weekday names. - Disabled days stay in the grid but cannot be selected. Explain the rule next to the calendar (“Weekdays only”): the dimmed color alone does not tell the user why.
API reference
Generated from the TypeScript source. className, style and children are accepted everywhere and omitted below.
Calendar
Calendar is a month grid for picking a date, several dates or a range, built on react-day-picker: set `mode` to "single", "multiple" or "range". For a date field in a form, open it from a button inside a Popover.
| Prop | Type | Default |
|---|---|---|
buttonVariant | "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | nullButton variant of the previous and next month arrows. | ghost |
CalendarDayButton
CalendarDayButton is the button of one day. Calendar uses it already; it is exported to wrap or restyle through the `components.DayButton` prop.
| Prop | Type | Default |
|---|---|---|
locale | Partial<DayPickerLocale>Locale of the `data-day` attribute's date; Calendar passes its own. | - |