# Calendar **Category**: react **URL**: https://www.heroui.com/docs/react/components/calendar **Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/react/components/(date-and-time)/calendar.mdx > Composable date picker with month grid, navigation, and year picker support built on React Aria Calendar *** ## Import ```tsx import { Calendar } from '@heroui/react'; ``` ### Usage ```tsx "use client"; import {Calendar} from "@heroui/react"; export function Basic() { return ( {(day) => {day}} {(date) => } ); } ``` ### Anatomy ```tsx import {Calendar} from '@heroui/react'; export default () => ( {(day) => {day}} {(date) => } ) ``` ### Year Picker `Calendar.YearPickerTrigger`, `Calendar.YearPickerGrid`, and their body/cell subcomponents provide an integrated year navigation pattern. ```tsx "use client"; import {Calendar} from "@heroui/react"; export function YearPicker() { return ( {(day) => {day}} {(date) => } {({year}) => } ); } ``` ### Default Value ```tsx "use client"; import {Calendar} from "@heroui/react"; import {parseDate} from "@internationalized/date"; export function DefaultValue() { return ( {(day) => {day}} {(date) => } ); } ``` ### Controlled Use controlled `value` and `focusedValue` for external state coordination and custom shortcuts. ```tsx "use client"; import type {DateValue} from "@internationalized/date"; import {Button, ButtonGroup, Calendar, Description} from "@heroui/react"; import { getLocalTimeZone, parseDate, startOfMonth, startOfWeek, today, } from "@internationalized/date"; import {useState} from "react"; import {useLocale} from "react-aria-components"; export function Controlled() { const [value, setValue] = useState(null); const [focusedDate, setFocusedDate] = useState(parseDate("2025-12-25")); const {locale} = useLocale(); return (
{(day) => {day}} {(date) => } Selected date: {value ? value.toString() : "(none)"}
); } ``` ### Min and Max Dates ```tsx "use client"; import {Calendar, Description} from "@heroui/react"; import {getLocalTimeZone, today} from "@internationalized/date"; export function MinMaxDates() { const now = today(getLocalTimeZone()); const minDate = now; const maxDate = now.add({months: 3}); return (
{(day) => {day}} {(date) => } Select a date between today and {maxDate.toString()}
); } ``` ### Unavailable Dates Use `isDateUnavailable` to block dates such as weekends, holidays, or booked slots. ```tsx "use client"; import type {DateValue} from "@internationalized/date"; import {Calendar, Description} from "@heroui/react"; import {isWeekend} from "@internationalized/date"; import {useLocale} from "react-aria-components"; export function UnavailableDates() { const {locale} = useLocale(); const isDateUnavailable = (date: DateValue) => isWeekend(date, locale); return (
{(day) => {day}} {(date) => } Weekends are unavailable
); } ``` ### Disabled ```tsx "use client"; import {Calendar, Description} from "@heroui/react"; import {getLocalTimeZone, today} from "@internationalized/date"; export function Disabled() { return (
{(day) => {day}} {(date) => } Calendar is disabled
); } ``` ### Read Only ```tsx "use client"; import {Calendar, Description} from "@heroui/react"; import {getLocalTimeZone, today} from "@internationalized/date"; export function ReadOnly() { return (
{(day) => {day}} {(date) => } Calendar is read-only
); } ``` ### Focused Value Programmatically control which date is focused using `focusedValue` and `onFocusChange`. ```tsx "use client"; import type {DateValue} from "@internationalized/date"; import {Button, Calendar, Description} from "@heroui/react"; import {parseDate} from "@internationalized/date"; import {useState} from "react"; export function FocusedValue() { const [focusedDate, setFocusedDate] = useState(parseDate("2025-06-15")); return (
{(day) => {day}} {(date) => } Focused: {focusedDate.toString()}
); } ``` ### Cell Indicators You can customize `Calendar.Cell` children and use `Calendar.CellIndicator` to display metadata like events. ```tsx "use client"; import {Calendar} from "@heroui/react"; import {getLocalTimeZone, isToday} from "@internationalized/date"; const datesWithEvents = [3, 7, 12, 15, 21, 28]; export function WithIndicators() { return ( {(day) => {day}} {(date) => ( {({formattedDate}) => ( <> {formattedDate} {(isToday(date, getLocalTimeZone()) || datesWithEvents.includes(date.day)) && ( )} )} )} ); } ``` ### Multiple Months Render multiple grids with `visibleDuration` and `offset` for booking and planning experiences. ```tsx "use client"; import {Calendar} from "@heroui/react"; import {getLocalTimeZone} from "@internationalized/date"; import React from "react"; import {CalendarStateContext, useLocale} from "react-aria-components"; function CalendarMonthHeading({offset = 0}: {offset?: number}) { const state = React.useContext(CalendarStateContext)!; const {locale} = useLocale(); const startDate = state.visibleRange.start; const monthDate = startDate.add({months: offset}); const dateObj = monthDate.toDate(getLocalTimeZone()); const monthYear = new Intl.DateTimeFormat(locale, {month: "long", year: "numeric"}).format( dateObj, ); return {monthYear}; } export function MultipleMonths() { return (
{(day) => {day}} {(date) => }
{(day) => {day}} {(date) => }
); } ``` ### International Calendars By default, Calendar displays dates using the calendar system for the user's locale. You can override this by wrapping your Calendar with `I18nProvider` and setting the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string). The example below shows the Indian calendar system: ```tsx "use client"; import {Calendar} from "@heroui/react"; import {getLocalTimeZone, today} from "@internationalized/date"; import {I18nProvider} from "react-aria-components"; export function InternationalCalendar() { return ( {(day) => {day}} {(date) => } {({year}) => } ); } ``` **Note:** The `onChange` event always returns a date in the same calendar system as the `value` or `defaultValue` (Gregorian if no value is provided), regardless of the displayed locale. This ensures your application logic works consistently with a single calendar system while still displaying dates in the user's preferred format. ### Custom Navigation Icons Pass children to `Calendar.NavButton` to replace the default chevron icons. ```tsx "use client"; import {Calendar} from "@heroui/react"; export function CustomIcons() { return ( {(day) => {day}} {(date) => } ); } ``` ### Real-World Example ```tsx "use client"; import type {DateValue} from "@internationalized/date"; import {Button, Calendar} from "@heroui/react"; import {getLocalTimeZone, isWeekend, today} from "@internationalized/date"; import {useState} from "react"; import {useLocale} from "react-aria-components"; export function BookingCalendar() { const [selectedDate, setSelectedDate] = useState(null); const {locale} = useLocale(); const bookedDates = [5, 6, 12, 13, 14, 20]; const isDateUnavailable = (date: DateValue) => { return isWeekend(date, locale) || bookedDates.includes(date.day); }; return (
{(day) => {day}} {(date) => ( {({formattedDate, isUnavailable}) => ( <> {formattedDate} {!isUnavailable && !isWeekend(date, locale) && bookedDates.includes(date.day) && } )} )}
Has bookings Weekend/Unavailable
{selectedDate ? ( ) : null}
); } ``` ### Custom Styles ```tsx "use client"; import {Calendar} from "@heroui/react"; export function CustomStyles() { return ( {(day) => {day}} {(date) => } {({year}) => } ); } ``` ## Related Components - **RangeCalendar**: Interactive month grid for selecting date ranges - **DateField**: Date input field with labels, descriptions, and validation - **DatePicker**: Composable date picker with date field trigger and calendar popover ## Styling ### Passing Tailwind CSS classes ```tsx import {Calendar} from '@heroui/react'; function CustomCalendar() { return ( {(day) => {day}} {(date) => } ); } ``` ### Customizing the component classes ```css @layer components { .calendar { @apply w-72 rounded-2xl border border-border bg-surface p-3 shadow-sm; } .calendar__heading { @apply text-sm font-semibold text-default-700; } .calendar__cell[data-selected="true"] { @apply bg-accent text-accent-foreground; } } ``` ### CSS Classes Calendar uses these classes in `packages/styles/components/calendar.css` and `packages/styles/components/calendar-year-picker.css`: - `.calendar` - Root container. - `.calendar__header` - Header row containing nav buttons and heading. - `.calendar__heading` - Current month label. - `.calendar__nav-button` - Previous/next navigation controls. - `.calendar__grid` - Main day grid. - `.calendar__grid-header` - Weekday header row wrapper. - `.calendar__grid-body` - Date rows wrapper. - `.calendar__header-cell` - Weekday header cell. - `.calendar__cell` - Interactive day cell. - `.calendar__cell-indicator` - Dot indicator inside a day cell. - `.calendar-year-picker__trigger` - Year picker toggle button. - `.calendar-year-picker__trigger-heading` - Heading text inside year picker trigger. - `.calendar-year-picker__trigger-indicator` - Indicator icon inside year picker trigger. - `.calendar-year-picker__year-grid` - Overlay grid of selectable years. - `.calendar-year-picker__year-cell` - Individual year option. ### Interactive States Calendar supports both pseudo-classes and React Aria data attributes: - **Selected**: `[data-selected="true"]` - **Today**: `[data-today="true"]` - **Unavailable**: `[data-unavailable="true"]` - **Outside month**: `[data-outside-month="true"]` - **Hovered**: `:hover` or `[data-hovered="true"]` - **Pressed**: `:active` or `[data-pressed="true"]` - **Focus visible**: `:focus-visible` or `[data-focus-visible="true"]` - **Disabled**: `:disabled` or `[data-disabled="true"]` ## API Reference ### Calendar Props Calendar inherits all props from React Aria [Calendar](https://react-spectrum.adobe.com/react-aria/Calendar.html). | Prop | Type | Default | Description | |------|------|---------|-------------| | `value` | `DateValue \| null` | - | Controlled selected date. | | `defaultValue` | `DateValue \| null` | - | Initial selected date (uncontrolled). | | `onChange` | `(value: DateValue) => void` | - | Called when selection changes. | | `focusedValue` | `DateValue` | - | Controlled focused date. | | `onFocusChange` | `(value: DateValue) => void` | - | Called when focus moves to another date. | | `minValue` | `DateValue` | Calendar-aware `1900-01-01` | Earliest selectable date. | | `maxValue` | `DateValue` | Calendar-aware `2099-12-31` | Latest selectable date. | | `isDateUnavailable` | `(date: DateValue) => boolean` | - | Marks dates as unavailable. | | `isDisabled` | `boolean` | `false` | Disables interaction and selection. | | `isReadOnly` | `boolean` | `false` | Keeps content readable but prevents selection changes. | | `isInvalid` | `boolean` | `false` | Marks the calendar as invalid for validation UI. | | `visibleDuration` | `{months?: number}` | `{months: 1}` | Number of visible months. | | `defaultYearPickerOpen` | `boolean` | `false` | Initial open state of internal year picker. | | `isYearPickerOpen` | `boolean` | - | Controlled year picker open state. | | `onYearPickerOpenChange` | `(isOpen: boolean) => void` | - | Called when year picker open state changes. | ### Composition Parts | Component | Description | |-----------|-------------| | `Calendar.Header` | Header container for navigation and heading. | | `Calendar.Heading` | Current month/year heading. | | `Calendar.NavButton` | Previous/next navigation control (`slot=\"previous\"` or `slot=\"next\"`). | | `Calendar.Grid` | Day grid for one month (`offset` supported for multi-month layouts). | | `Calendar.GridHeader` | Weekday header container. | | `Calendar.GridBody` | Date cell body container. | | `Calendar.HeaderCell` | Weekday label cell. | | `Calendar.Cell` | Individual date cell. | | `Calendar.CellIndicator` | Optional indicator element for custom metadata. | | `Calendar.YearPickerTrigger` | Trigger to toggle year-picker mode. | | `Calendar.YearPickerTriggerHeading` | Localized heading content inside the year-picker trigger. | | `Calendar.YearPickerTriggerIndicator` | Toggle icon inside the year-picker trigger. | | `Calendar.YearPickerGrid` | Overlay year selection grid container. | | `Calendar.YearPickerGridBody` | Body renderer for year grid cells. | | `Calendar.YearPickerCell` | Individual year option cell. | ### Calendar.Cell Render Props When `Calendar.Cell` children is a function, React Aria render props are available: | Prop | Type | Description | |------|------|-------------| | `formattedDate` | `string` | Localized day label for the cell. | | `isSelected` | `boolean` | Whether the date is selected. | | `isUnavailable` | `boolean` | Whether the date is unavailable. | | `isDisabled` | `boolean` | Whether the cell is disabled. | | `isOutsideMonth` | `boolean` | Whether the date belongs to adjacent month. | For a complete list of supported calendar systems and their identifiers, see: - [React Aria Calendar Implementations](https://react-aria.adobe.com/internationalized/date/Calendar#implementations) - [React Aria International Calendars](https://react-aria.adobe.com/Calendar#international-calendars) ### Related packages - [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) — date types (`CalendarDate`, `CalendarDateTime`, `ZonedDateTime`) and utilities used by all date components - [`I18nProvider`](https://react-aria.adobe.com/I18nProvider) — override locale for a subtree - [`useLocale`](https://react-aria.adobe.com/useLocale) — read the current locale and layout direction