Manual UI Templates Calendar

Calendar

elements man ui/templates/calendar

A month grid for picking one date, several dates or a range, with keyboard navigation across months.

Example
import { Calendar } from "@elements/ui/calendar"; <Calendar value={form.due} /> <Calendar mode="multiple" values={form.days} max={5} /> <Calendar mode="range" from={trip.from} to={trip.to} numberOfMonths={2} /> <Calendar captionLayout="dropdown" startMonth="1930-01" disabled={{ after: today }} />

Parts

Part What it is
Calendar The template: one grid per shown month, its caption and navigation, and a footer live region.
.calendar-month One month: caption and grid. data-month is YYYY-MM.
.calendar-caption Previous button, the month label (a polite live region) or the month and year dropdowns, next button.
.calendar-day A day cell (role=gridcell) carrying the day's state as data attributes.
.calendar-day-button The day's button; the only one in the Tab order is the focus target.
.calendar-week-number A week number rowheader (showWeekNumber); its number is a .calendar-week-number-button with weekNumberButtons.
.calendar-nav-button Previous and next month, plus .is-previous-year and .is-next-year with yearButtons.
.calendar-help A polite live region for the help text once focus rests on a day (help).
.calendar-footer A polite live region for the footer text and slot.

Attributes

Attribute Type Default Description
mode "single" | "multiple" | "range" | "none" "single" What a click selects. none selects nothing; onDayClick still fires.
value ISODate (two-way) "" The selected date in single mode, "YYYY-MM-DD".
values ISODate[] (two-way) [] The selected dates in multiple mode.
from ISODate (two-way) "" Range start.
to ISODate (two-way) "" Range end.
month ISODate (two-way) "" The first month shown (YYYY-MM or any date in it). Unset: defaultMonth, else the selection, else today.
defaultMonth ISODate "" The first month shown when month is unset.
startMonth ISODate "" The earliest month the buttons, keyboard and dropdowns reach.
endMonth ISODate "" The latest month they reach.
fromMonth, toMonth, fromYear, toYear ISODate, ISODate, number, number "", "", 0, 0 Older names for the bounds: fromMonth and toMonth are startMonth and endMonth, fromYear starts at its January, toYear ends at its December. startMonth and endMonth win.
numberOfMonths number 1 Months shown side by side; they stack on a phone.
pagedNavigation boolean false Previous and next move by numberOfMonths.
reverseMonths boolean false Shows the months latest first.
disabled Matcher | Matcher[] false Days that cannot be selected or focused: true, a date, dates, {from,to}, {before}, {after}, {before,after}, {dayOfWeek}, or (date) => boolean.
hidden Matcher | Matcher[] false Days not rendered; the keyboard skips them.
modifiers Record<string, Matcher | Matcher[]> {} Custom day states, written to data-modifiers on the cell for styling.
required boolean false The selection cannot be cleared by clicking it.
min number 0 Multiple: fewest dates. Range: fewest nights.
max number 0 Multiple: most dates (one more restarts). Range: most nights.
excludeDisabled boolean false Range: a range over a disabled day restarts at the clicked day.
resetOnSelect boolean false Range: the next click after a complete range starts a new one.
showOutsideDays boolean true Shows the adjacent months' days, dimmed and selectable.
fixedWeeks boolean false Always six weeks, so the height never changes.
showWeekNumber boolean false A week number column.
weekNumberButtons boolean false Each week number is a button; onWeekNumberClick reports its week.
hideWeekdays boolean false Hides the weekday header row.
weekStartsOn number -1 0 Sunday to 6 Saturday; -1 follows the locale.
firstWeekContainsDate number 0 Week 1 holds this day of January; 0 follows the locale.
isoWeek boolean false ISO 8601 weeks: Monday first, ISO week numbers.
broadcastCalendar boolean false US broadcast calendar: Monday first, whole weeks ending on the month's last Sunday.
captionLayout "label" | "dropdown" | "dropdown-months" | "dropdown-years" "label" Native month and year selects in the caption.
reverseYears boolean false Newest year first in the year dropdown.
dropdownStyle "native" | "listbox" "native" The caption dropdowns as native selects, or as the library's Select (combobox and listbox).
navLayout "around" | "after" "around" Buttons beside the caption, or both after it in the last month.
hideNavigation boolean false No previous and next buttons.
yearButtons boolean false Previous and next year buttons beside the month buttons (WAI-ARIA date picker dialog).
disableNavigation boolean false Buttons and dropdowns disabled; the keyboard stays in the shown months.
animate boolean false Slides the weeks on a month change; off under reduced motion.
locale string "" BCP 47 tag for names, first weekday and week rule (Intl). Empty uses the page's lang.
numerals string "" Numbering system: latn, arab, deva, thai and others; ethi writes Ge'ez numerals.
calendar string "" An Intl calendar the grid follows: persian, islamic-umalqura, buddhist, ethiopic, hebrew. Values stay Gregorian ISO dates.
dir "" | "ltr" | "rtl" "" Text direction; the arrows follow it.
today ISODate "" The date treated as today; the device's date when empty.
timeZone string "" An IANA time zone ("Pacific/Auckland"): today is the date there. Dates stay plain ISO days.
footer string "" Text in the footer live region, such as the picked date.
help string "" Keyboard help announced in a polite live region once focus rests on a day.
label string "" aria-label on the root.
role "" | "application" | "dialog" | "group" "" A role for the root.
autoFocus boolean false Focuses the focus target when the calendar appears.
labels Partial<CalendarLabels> {} Accessible names: nav, previous, next, previousYear, nextYear, monthDropdown, yearDropdown, weekNumberHeader, weekNumber(n), weekday(date, locale), day(date, modifiers, locale), grid(month, locale).
formatters Partial<CalendarFormatters> {} Display text: caption, day, weekday, weekNumber, weekNumberHeader, monthDropdown, yearDropdown.
dayContent (date, modifiers) => string () => "" A second line inside each day button, such as a price; aria-hidden, and an empty string shows none.
class string "" Classes on the root. Set --calendar-cell-size through one for larger cells.
attrs Record<string, string | number | boolean | undefined> {} Other attributes for the root: id, title, data-*, aria-* (aria-labelledby).
onValueChange (value: ISODate) => void () => {} The calendar changed value.
onValuesChange (values: ISODate[]) => void () => {} The calendar changed values.
onRangeChange (range: { from; to }) => void () => {} The calendar changed the range.
onSelect (date: ISODate, modifiers: DayModifiers) => void () => {} A day was activated in a selection mode, even when the rules left the selection as it was.
onMonthChange (month: ISODate) => void () => {} The first shown month changed.
onPrevClick, onNextClick (month: ISODate) => void () => {} A navigation button moved the months.
onPrevYearClick, onNextYearClick (month: ISODate) => void () => {} A year button moved the months (yearButtons).
onWeekNumberClick (week: number, dates: ISODate[], e: MouseEvent) => void () => {} A week number button was clicked (weekNumberButtons): its number and its seven dates.
onDayClick (date, modifiers, e: MouseEvent) => void () => {} A day was clicked. e.preventDefault() cancels the selection.
onDayKeyDown (date, modifiers, e: KeyboardEvent) => void () => {} A key on a day. e.preventDefault() cancels the calendar's handling.
onDayFocus, onDayBlur (date, modifiers, e: FocusEvent) => void () => {} A day gained or lost focus.
onDayMouseEnter, onDayMouseLeave (date, modifiers, e: PointerEvent) => void () => {} The pointer entered or left a day.

Slots

Slot Content
footer Content under the months, inside the polite live region.

Keyboard

Keys Action
ArrowLeft / ArrowRight Previous / next day (flipped under rtl).
ArrowUp / ArrowDown Same day of the previous / next week.
Shift + ArrowLeft / ArrowRight Same day of the previous / next month.
Shift + ArrowUp / ArrowDown Same day of the previous / next year.
PageUp / PageDown Same day of the previous / next month; a missing day lands on the month's last day.
Shift + PageUp / PageDown Same day of the previous / next year.
Home / End First / last day of the week.
Enter / Space Selects the focused day.
Tab Moves between the navigation, the dropdowns and the one focusable day.

Data attributes

Attribute Values On Description
data-mode the mode root
data-animate "before" | "after" root during a month animation
data-month YYYY-MM .calendar-month
data-day YYYY-MM-DD .calendar-day
data-selected present .calendar-day
data-today present .calendar-day
data-outside present .calendar-day another month's day
data-disabled present .calendar-day
data-hidden present .calendar-day an empty cell
data-focused present .calendar-day
data-range-start, data-range-middle, data-range-end present .calendar-day
data-modifiers space-separated names .calendar-day style with [data-modifiers~="booked"]

Accessibility

  • Each month is a role=grid named by its month and year; aria-multiselectable in multiple and range modes.
  • Weekday headers are columnheaders named with the full weekday; week numbers are rowheaders named "Week 44".
  • Days are gridcells with aria-selected on the selection; each button is named like "Today, Thursday, October 29, 2026, selected".
  • One Tab stop across all shown months: the focused day, else the selection, else today, else the first enabled day.
  • The month label is a polite live region, so a month change is announced; the footer is a polite live region for selection feedback.
  • Disabled days are disabled buttons with aria-disabled on the cell and are skipped by the keyboard.

See also