import {
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,
CalendarViewButton,- Browser support
- Newly available 2024
- Chrome 125
- Edge 125
- Firefox 128
- Safari 18
- Safari on iOS 18
- Bundle size
- Relative colors
- Oklab and OkLCh
- Scroll snap
- scrollend — has a fallback in the code, not counted in the minimum
- scrollbar-width — covered by a -webkit- fallback, not counted in the minimum
- inert
- Intl.Locale
- Intl.Locale info — has a fallback in the code, not counted in the minimum
- Resize observer
- aspect-ratio
- Logical properties
- :dir() — only right-to-left layouts depend on it
- :focus-visible
- :where()
- contain
- scroll-behavior
Summary
Calendar is an advanced interactive compound component for coordinated date selection across day, month, and year views. It is the consumer-facing orchestration layer on top of the lower-level picker family.
Imports
import {
Calendar,
type CalendarProps,
type CalendarView,
type CalendarSelection,
type CalendarDatesDisabled,
} from '@vega-ui/react';Exported Types
CalendarPropsCalendarViewCalendarSelectionCalendarDatesDisabled
Minimal Composition
import {
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,
CalendarViewButton,Required Parts
Calendar: root state and date-selection model
Optional Parts
CalendarHeader,CalendarPrevButton,CalendarNextButton: navigation chrome; previous and next follow the current viewCalendarViewButtonGroup,CalendarViewButton: month and year view togglesCalendarMonthLabel,CalendarYearLabel: labels of the visible month and yearCalendarContent: wrapper for the viewsCalendarDays,CalendarMonths,CalendarYears: day, month, and year viewsCalendarDay,CalendarMonth,CalendarYear: cell templates of the views, withuseCalendarDayContext,useCalendarMonthContext,useCalendarYearContext
Composition Order
Typical composition:
CalendarCalendarHeaderwithCalendarPrevButton,CalendarViewButtonGroup,CalendarNextButtonCalendarContentCalendarDays,CalendarMonths,CalendarYears; only the currentviewis visible
Variants
- Selection:
single,multiple,range - View switching: day, month, year
- Density:
compactplus size variants - Composition depth: default views versus custom cell templates
- Locale and calendar system:
localeandcalendarroot props, defaulting to the runtime locale and the Gregorian calendar; see Dates And Calendar Systems
Edge Cases
- Selection mode changes the value shape.
- Disabled-date constraints can come from a value list or predicate logic.
- Custom cell templates should be retested for keyboard flow, overflow days, and visible period changes.
value,defaultValue,min,max,month, anddisabledDatesare ISOYYYY-MM-DDstrings in every calendar system; only the grid and labels followcalendar.- Non-Gregorian calendars come from
createCalendarSystem; see Dates And Calendar Systems.
Common Mistakes
- Forgetting that
selectionchanges the expected value model. - Passing
Dateobjects, timestamps, or display-calendar strings instead of ISOYYYY-MM-DDstrings. - Reading the day number from the ISO
dateof a cell instead oflabelorfields.day; it is wrong in non-Gregorian calendars. - Combining
min,max, anddisabledDateswithout validating the resulting UX.
Examples
Basic
Basic: single date in a locale
The full composition: header with navigation and view switches, then the day, month, and year views. locale sets the month and weekday names and the first day of the week; defaultValue is an ISO day and also opens its month. The navigation buttons and the views have no built-in names, so they get aria-labels in the language of the calendar.
import {
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,
CalendarViewButton,Controlled/Stateful
Controlled/Stateful: value and visible month
value and month are both controlled, so a "Today" button can select today and scroll to it in one step. Navigating only calls onChangeMonth, which the readout below the calendar follows; the value changes only when a day is picked.
import {
Button,
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,Controlled/Stateful: range with a summary
In range mode the value is a [start, end] tuple; '' marks a bound that is not picked yet. The bounds always come in order, start before end, whichever was picked first, so the summary can count nights without sorting.
import {
Button,
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,Controlled/Stateful: multiple dates with a limit
selection='multiple' makes the value an array of ISO days in the order they were picked. A controlled value can refuse a change: here onChangeValue ignores a sixth day, so the calendar keeps showing five.
import {
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,
CalendarViewButton,Form/Integration
Form/Integration: submit the date with a form
Calendar has no form value of its own and no required: keep the ISO day in state, submit it with a hidden input, and read it back with FormData. The empty check runs on submit, and its message is linked to the day grid with aria-describedby; the reset button clears the state through the form's reset event.
import {
Button,
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,Layout/Overlay
Layout/Overlay: calendar in a popover
A date picker made of a trigger and a compact calendar in Popover. The popover is controlled, so it closes as soon as a day is picked; the trigger's accessible name keeps the field name next to the chosen date.
import {
Button,
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,Error
Error: range across a blocked day
disabledDates stops a blocked day from being picked, but a range can still span it. Validate the range in the app, show the error only while the value is wrong, and link it to the day grid with aria-describedby.
import {
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,
CalendarViewButton,Disabled
Disabled: whole calendar while saving
disabled turns off selection and navigation in every view, here while the new meeting date is being saved. The status next to the calendar says what is happening; a disabled calendar alone does not.
import {
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,
CalendarViewButton,Disabled: booking window, weekends and holidays
Days before min and after max are disabled, and the previous / next buttons hide at those months. The disabledDates predicate closes weekends and a list of holidays; an array of ISO days works too when the list is all there is. The rule is written next to the calendar and linked with aria-describedby, because a disabled day does not say why.
import {
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,
CalendarViewButton,Edge
Edge: overflow days
includeOverflowDays fills the empty cells with days of the previous and next months. They are shown but cannot be selected; the day template styles them through inMonth.
import {
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,
CalendarViewButton,Edge: min and max inside one month
When min and max fall in the same month, both previous and next buttons hide and only the days between them can be picked; keyboard focus starts on the first available day. The calendar does not move to min by itself: without defaultMonth it opens on the current month, even when that month is out of range.
import {
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,
CalendarViewButton,Edge: 13-month year
With a calendar system from createCalendarSystem (see Calendar System Adapter), the month view follows that calendar. The Hebrew year 5784 is a leap year, so CalendarMonths shows 13 months, Adar I and Adar II included. The value is still an ISO day, as the readout shows.
import { createCalendarSystem } from '@vega-ui/i18n';
import {
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonth,
CalendarMonthLabel,
CalendarMonths,
CalendarNextButton,
CalendarPrevButton,Anatomy
Overview
Calendar owns the visible month, the current view, selection state, disabled-date rules, locale and calendar system, and keyboard coordination across the day, month, and year views.
Required Parts
Calendar
Root provider for the date-selection model.
- Required: yes
- Owns: view state, visible month, selection state, disabled-date logic,
localeandcalendar
Optional Parts
CalendarHeader
Header wrapper for navigation and view switching.
CalendarPrevButton / CalendarNextButton
Show the previous or next page of the current view: the previous or next month in the days, the previous or next page of years in the years. Hidden in the months view, and in the days when the previous or next month is outside min / max.
CalendarViewButtonGroup
Keeps the view buttons together between the previous and next buttons.
CalendarViewButton
view='month' or view='year' toggles that view; pressing it again goes back to the days. It is pressed (aria-pressed) while its view is shown.
CalendarMonthLabel / CalendarYearLabel
Visible month and year in the locale and calendar system of the root.
CalendarContent
Main content wrapper for the views.
CalendarDays
Day view. Its children are CalendarWeekdays and CalendarWeeks.
CalendarWeekdays
Row of weekday names in the locale of the root, starting on the first day of its week. Prop: format ('long' | 'short' | 'narrow', default 'short'). Its required children are the template of a weekday, usually <CalendarWeekday />; read the weekday with useCalendarWeekdayContext().
CalendarWeeks
Day grid, week by week, swipeable between months. Props: format, includeOverflowDays.
CalendarMonths
Month view: the months of the visible year, 12 or 13 depending on the calendar system. Props: cols, format.
CalendarYears
Year view: pages of years, swipeable. Prop: format.
CalendarDay / CalendarMonth / CalendarYear
Cell templates. Children of CalendarWeeks, CalendarMonths, and CalendarYears are required and rendered once per cell inside a cell context; usually <CalendarDay />, <CalendarMonth />, or <CalendarYear />, which shows the formatted label. Read the cell with useCalendarDayContext(), useCalendarMonthContext(), or useCalendarYearContext().
Composition Order
Typical composition:
CalendarCalendarHeaderwith navigation buttons and view buttonsCalendarContentCalendarDays,CalendarMonths,CalendarYears; only the current view is visible
Valid Composition Patterns
The month and year views are optional. A day-only calendar keeps CalendarDays alone in CalendarContent and shows the month and year as plain text between the navigation buttons; without CalendarMonths and CalendarYears there is nothing for a CalendarViewButton to open, so leave it out. The full composition is in Minimal Composition.
import {
Calendar,
CalendarContent,
CalendarDay,
CalendarDays,
CalendarHeader,
CalendarMonthLabel,
CalendarNextButton,
CalendarPrevButton,
CalendarWeekday,
CalendarWeekdays,
CalendarWeeks,Invalid Composition Patterns
View parts outside Calendar
The views and cell templates rely on root context. Moving them outside Calendar breaks coordination.
Custom cell templates without CalendarDay
A template must render CalendarDay (or CalendarMonth, CalendarYear) as the cell; content goes inside it. Without it the grid loses selection, focus, and disabled states.
Treating day, month, and year views as isolated widgets
They are coordinated views of the same calendar state model, not unrelated components.