Calendar

A single-date calendar for selecting dates with month navigation, locale support, and customizable day cells.

Import

import { Calendar } from 'heroui-native-pro';

Anatomy

With Heading

<Calendar>
  <Calendar.Header>
    <Calendar.Heading />
    <Calendar.NavButton slot="previous" />
    <Calendar.NavButton slot="next" />
  </Calendar.Header>
  <Calendar.Grid>
    <Calendar.GridHeader>
      {(day) => <Calendar.HeaderCell day={day} />}
    </Calendar.GridHeader>
    <Calendar.GridBody>
      {(date) => <Calendar.Cell date={date} />}
    </Calendar.GridBody>
  </Calendar.Grid>
</Calendar>

With Year Picker

<Calendar>
  <Calendar.Header>
    <Calendar.YearPickerTrigger>
      <Calendar.YearPickerTriggerHeading />
      <Calendar.YearPickerTriggerIndicator />
    </Calendar.YearPickerTrigger>
    <Calendar.NavButton slot="previous" />
    <Calendar.NavButton slot="next" />
  </Calendar.Header>
  <Calendar.Grid>
    <Calendar.GridHeader>
      {(day) => <Calendar.HeaderCell day={day} />}
    </Calendar.GridHeader>
    <Calendar.GridBody>
      {(date) => <Calendar.Cell date={date} />}
    </Calendar.GridBody>
  </Calendar.Grid>
  <Calendar.YearPickerGrid>
    <Calendar.YearPickerGridBody>
      {(renderProps) => (
        <Calendar.YearPickerCell
          year={renderProps.year}
          isSelected={renderProps.isSelected}
        />
      )}
    </Calendar.YearPickerGridBody>
  </Calendar.YearPickerGrid>
</Calendar>
  • Calendar: Root container that manages single-date selection state, locale, and animation settings. Supports controlled and uncontrolled modes with min/max constraints and date unavailability filtering.
  • Calendar.Header: Toolbar row for navigation controls and the month/year title.
  • Calendar.Heading: Month/year label text. The primitive computes the heading string automatically when children are omitted.
  • Calendar.NavButton: Previous or next month navigation button. Renders a default chevron icon using the theme accent color; override via iconProps or pass custom children.
  • Calendar.Grid: Month grid container that provides internal grid context to the header and body.
  • Calendar.GridHeader: Weekday labels row. Requires a render function (day: string) => ReactElement as children.
  • Calendar.GridBody: Day cells matrix. Requires a render function (date: CalendarDate) => ReactElement as children.
  • Calendar.HeaderCell: Single weekday header cell. Stringifiable children are wrapped in HeaderCellLabel; pass day when omitting children.
  • Calendar.HeaderCellLabel: Text slot for a weekday header cell label.
  • Calendar.Cell: Selectable day cell. By default renders CellBody with CellLabel inside. Pass a render function as children to customize the cell content.
  • Calendar.CellBody: Inner rounded region of a day cell with press scale animation. Pass cellRenderProps for data attribute selectors.
  • Calendar.CellLabel: Day number label. Pass cellRenderProps for data attribute selectors.
  • Calendar.CellIndicator: Dot marker under a day cell (e.g. for events). Pass cellRenderProps for data-selected styling.
  • Calendar.YearPickerTrigger: Pressable trigger that replaces Heading to toggle the year picker overlay.
  • Calendar.YearPickerTriggerHeading: Month/year label text inside the year picker trigger.
  • Calendar.YearPickerTriggerIndicator: Animated chevron icon indicating the year picker open state.
  • Calendar.YearPickerGrid: Overlay container positioned over the month grid when the year picker is open.
  • Calendar.YearPickerGridBody: Scrollable list of year cells inside the year picker grid.
  • Calendar.YearPickerCell: Pressable year cell that selects a year and closes the picker.

Usage

Basic Usage

The Calendar component uses compound parts to build a date picker. GridHeader and GridBody require render function children.

<Calendar accessibilityLabel="Event date">
  <Calendar.Header>
    <Calendar.Heading />
    <Calendar.NavButton slot="previous" />
    <Calendar.NavButton slot="next" />
  </Calendar.Header>
  <Calendar.Grid>
    <Calendar.GridHeader>
      {(day) => <Calendar.HeaderCell day={day} />}
    </Calendar.GridHeader>
    <Calendar.GridBody>
      {(date) => <Calendar.Cell date={date} />}
    </Calendar.GridBody>
  </Calendar.Grid>
</Calendar>

Default Value

Set an initial selected date with defaultValue using @internationalized/date.

<Calendar defaultValue={parseDate('2026-06-19')}>
  <Calendar.Header>
    <Calendar.Heading />
    <Calendar.NavButton slot="previous" />
    <Calendar.NavButton slot="next" />
  </Calendar.Header>
  <Calendar.Grid>
    <Calendar.GridHeader>
      {(day) => <Calendar.HeaderCell day={day} />}
    </Calendar.GridHeader>
    <Calendar.GridBody>
      {(date) => <Calendar.Cell date={date} />}
    </Calendar.GridBody>
  </Calendar.Grid>
</Calendar>

Controlled Value

Use value and onChange to control the selected date externally.

const [date, setDate] = useState(today(getLocalTimeZone()));

<Calendar value={date} onChange={setDate}>
  <Calendar.Header>
    <Calendar.Heading />
    <Calendar.NavButton slot="previous" />
    <Calendar.NavButton slot="next" />
  </Calendar.Header>
  <Calendar.Grid>
    <Calendar.GridHeader>
      {(day) => <Calendar.HeaderCell day={day} />}
    </Calendar.GridHeader>
    <Calendar.GridBody>
      {(date) => <Calendar.Cell date={date} />}
    </Calendar.GridBody>
  </Calendar.Grid>
</Calendar>;

Min and Max Dates

Restrict navigation and selection to a date range using minValue and maxValue.

const now = today(getLocalTimeZone());

<Calendar minValue={now} maxValue={now.add({ months: 2 })}>
  <Calendar.Header>
    <Calendar.Heading />
    <Calendar.NavButton slot="previous" />
    <Calendar.NavButton slot="next" />
  </Calendar.Header>
  <Calendar.Grid>
    <Calendar.GridHeader>
      {(day) => <Calendar.HeaderCell day={day} />}
    </Calendar.GridHeader>
    <Calendar.GridBody>
      {(date) => <Calendar.Cell date={date} />}
    </Calendar.GridBody>
  </Calendar.Grid>
</Calendar>;

Unavailable Dates

Mark specific dates as unavailable using the isDateUnavailable callback.

const isDateUnavailable = (date: DateValue) => isWeekend(date, 'en-US');

<Calendar isDateUnavailable={isDateUnavailable}>
  <Calendar.Header>
    <Calendar.Heading />
    <Calendar.NavButton slot="previous" />
    <Calendar.NavButton slot="next" />
  </Calendar.Header>
  <Calendar.Grid>
    <Calendar.GridHeader>
      {(day) => <Calendar.HeaderCell day={day} />}
    </Calendar.GridHeader>
    <Calendar.GridBody>
      {(date) => <Calendar.Cell date={date} />}
    </Calendar.GridBody>
  </Calendar.Grid>
</Calendar>;

With Cell Indicators

Use a render function on Calendar.Cell to add dot indicators under specific dates.

<Calendar.GridBody>
  {(date) => (
    <Calendar.Cell date={date}>
      {(renderProps) => (
        <Calendar.CellBody cellRenderProps={renderProps}>
          <Calendar.CellLabel cellRenderProps={renderProps}>
            {renderProps.formattedDate}
          </Calendar.CellLabel>
          {datesWithEvents.includes(date.day) && (
            <Calendar.CellIndicator cellRenderProps={renderProps} />
          )}
        </Calendar.CellBody>
      )}
    </Calendar.Cell>
  )}
</Calendar.GridBody>

International Calendar

Pass a BCP 47 locale string to render the calendar in a different language and calendar system.

<Calendar locale="hi-IN-u-ca-indian">
  <Calendar.Header>
    <Calendar.Heading />
    <Calendar.NavButton slot="previous" />
    <Calendar.NavButton slot="next" />
  </Calendar.Header>
  <Calendar.Grid>
    <Calendar.GridHeader>
      {(day) => <Calendar.HeaderCell day={day} />}
    </Calendar.GridHeader>
    <Calendar.GridBody>
      {(date) => <Calendar.Cell date={date} />}
    </Calendar.GridBody>
  </Calendar.Grid>
</Calendar>

Disabled State

Disable the entire calendar and all navigation controls.

<Calendar isDisabled>
  <Calendar.Header>
    <Calendar.Heading />
    <Calendar.NavButton slot="previous" />
    <Calendar.NavButton slot="next" />
  </Calendar.Header>
  <Calendar.Grid>
    <Calendar.GridHeader>
      {(day) => <Calendar.HeaderCell day={day} />}
    </Calendar.GridHeader>
    <Calendar.GridBody>
      {(date) => <Calendar.Cell date={date} />}
    </Calendar.GridBody>
  </Calendar.Grid>
</Calendar>

Year Picker

Add a year picker overlay by replacing Heading with YearPickerTrigger and adding a YearPickerGrid inside the root.

<Calendar>
  <Calendar.Header>
    <Calendar.YearPickerTrigger>
      <Calendar.YearPickerTriggerHeading />
      <Calendar.YearPickerTriggerIndicator />
    </Calendar.YearPickerTrigger>
    <Calendar.NavButton slot="previous" />
    <Calendar.NavButton slot="next" />
  </Calendar.Header>
  <Calendar.Grid>
    <Calendar.GridHeader>
      {(day) => <Calendar.HeaderCell day={day} />}
    </Calendar.GridHeader>
    <Calendar.GridBody>
      {(date) => <Calendar.Cell date={date} />}
    </Calendar.GridBody>
  </Calendar.Grid>
  <Calendar.YearPickerGrid>
    <Calendar.YearPickerGridBody>
      {(renderProps) => (
        <Calendar.YearPickerCell
          year={renderProps.year}
          isSelected={renderProps.isSelected}
        />
      )}
    </Calendar.YearPickerGridBody>
  </Calendar.YearPickerGrid>
</Calendar>

Example

import {
  getLocalTimeZone,
  isToday,
  parseDate,
  today,
  type DateValue,
} from '@internationalized/date';
import { Calendar } from 'heroui-native-pro';
import { useState } from 'react';
import { View } from 'react-native';

const datesWithEvents = [3, 7, 12, 15, 21, 28];

export default function CalendarExample() {
  const [date, setDate] = useState<DateValue>(parseDate('2026-06-19'));

  return (
    <View className="flex-1 justify-center px-5">
      <Calendar value={date} onChange={setDate} accessibilityLabel="Event date">
        <Calendar.Header>
          <Calendar.Heading />
          <Calendar.NavButton slot="previous" />
          <Calendar.NavButton slot="next" />
        </Calendar.Header>
        <Calendar.Grid>
          <Calendar.GridHeader>
            {(day) => <Calendar.HeaderCell>{day}</Calendar.HeaderCell>}
          </Calendar.GridHeader>
          <Calendar.GridBody>
            {(date) => (
              <Calendar.Cell date={date}>
                {(renderProps) => (
                  <Calendar.CellBody cellRenderProps={renderProps}>
                    <Calendar.CellLabel cellRenderProps={renderProps}>
                      {renderProps.formattedDate}
                    </Calendar.CellLabel>
                    {(isToday(date, getLocalTimeZone()) ||
                      datesWithEvents.includes(date.day)) && (
                      <Calendar.CellIndicator cellRenderProps={renderProps} />
                    )}
                  </Calendar.CellBody>
                )}
              </Calendar.Cell>
            )}
          </Calendar.GridBody>
        </Calendar.Grid>
      </Calendar>
    </View>
  );
}

API Reference

Calendar

proptypedefaultdescription
childrenReact.ReactNode | ((props: { state: CalendarState }) => React.ReactNode)-Calendar content or render function receiving calendar state
valueDateValue | null-Controlled selected date
defaultValueDateValue | null-Default selected date for uncontrolled usage
minValueDateValue | null-Minimum selectable date; disables earlier dates and navigation
maxValueDateValue | null-Maximum selectable date; disables later dates and navigation
isDateUnavailable(date: DateValue) => boolean-Callback to mark specific dates as unavailable
isDisabledbooleanfalseWhether the entire calendar is disabled
isReadOnlybooleanfalseWhether the calendar value is immutable
isInvalidboolean-Whether the current selection is invalid
firstDayOfWeek'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat'-Override the first day of the week
localestring-BCP 47 locale; defaults to the environment locale
isYearPickerOpenboolean-Controlled open state for the year picker overlay
defaultYearPickerOpenbooleanfalseInitial open state for the year picker in uncontrolled mode
classNamestring-Additional CSS classes for the root container
animationAnimationRootDisableAll-Animation configuration for the calendar subtree
onChange(value: MappedDateValue<DateValue>) => void-Handler called when the selected date changes
onYearPickerOpenChange(isOpen: boolean) => void-Handler called when the year picker open state changes
...ViewPropsViewProps-All standard React Native View props are supported

AnimationRootDisableAll

Animation configuration for the Calendar root. Can be:

  • "disable-all": Disable all animations including children (cascades down)
  • undefined: Use default animations

Calendar.Header

proptypedefaultdescription
childrenReact.ReactNode-Header content (Heading, NavButtons, etc.)
classNamestring-Additional CSS classes for the header row container
...ViewPropsViewProps-All standard React Native View props are supported

Calendar.Heading

proptypedefaultdescription
childrenReact.ReactNode-Custom heading text; auto-computed month/year when omitted
classNamestring-Additional CSS classes for the heading text
...TextPropsTextProps-All standard React Native Text props are supported

Calendar.NavButton

proptypedefaultdescription
childrenReact.ReactNode-Custom icon content; replaces the default chevron when provided
slot'previous' | 'next'-Navigation direction; determines which chevron icon is rendered
isDisabledboolean-Merged with calendar isDisabled and range boundary state
classNamestring-Additional CSS classes for the pressable
iconPropsCalendarNavButtonIconProps-Overrides for the built-in chevron; ignored with custom children
...PressablePropsPressableProps-All standard React Native Pressable props are supported

CalendarNavButtonIconProps

proptypedefaultdescription
sizenumber18Icon size in logical pixels
colorstringTheme accentIcon stroke/fill color

Calendar.Grid

proptypedefaultdescription
childrenReact.ReactNode-Grid content (GridHeader, GridBody)
offsetDateDuration-Offset from the visible range start for multi-month grids
weekdayStyle'narrow' | 'short' | 'long'-Weekday label format
classNamestring-Additional CSS classes for the grid container
...ViewPropsViewProps-All standard React Native View props are supported

Calendar.GridHeader

proptypedefaultdescription
children(day: string) => React.ReactElement-Render function called for each weekday label (required)
classNamestring-Additional CSS classes for the weekday row wrapper
...ViewPropsViewProps-All standard React Native View props are supported

Calendar.GridBody

proptypedefaultdescription
children(date: CalendarDate) => React.ReactElement-Render function called for each day in the month (required)
classNamestring-Additional CSS classes for the grid body
...ViewPropsViewProps-All standard React Native View props are supported

Calendar.HeaderCell

proptypedefaultdescription
childrenReact.ReactNode-Custom cell content; stringifiable children are wrapped in HeaderCellLabel
daystring-Weekday label string from GridHeader's render callback; used when children is omitted
classNamestring-Additional CSS classes for the header cell container
...ViewPropsViewProps-All standard React Native View props are supported

Calendar.HeaderCellLabel

proptypedefaultdescription
childrenReact.ReactNode-Weekday label text
classNamestring-Additional CSS classes for the label text
...TextPropsTextProps-All standard React Native Text props are supported

Calendar.Cell

proptypedefaultdescription
dateCalendarDate-The calendar date this cell represents (required)
childrenReact.ReactNode | ((renderProps: CalendarCellRenderProps) => React.ReactNode)-Custom cell content; defaults to CellBody with CellLabel inside
isDisabledboolean-Merged with calendar isDisabled and cell-specific disabled state
classNamestring-Additional CSS classes for the day cell pressable
...PressablePropsPressableProps-All standard React Native Pressable props are supported

CalendarCellRenderProps

Render props received by the Calendar.Cell children render function.

propertytypedescription
dateCalendarDateThe calendar date for this cell
formattedDatestringLocale-formatted day number string
isSelectedbooleanWhether this date is currently selected
isTodaybooleanWhether this date is today
isDisabledbooleanWhether this date is disabled
isUnavailablebooleanWhether this date is unavailable via isDateUnavailable
isOutsideMonthbooleanWhether this date is outside the currently visible month
isFocusedbooleanWhether this date is currently focused
isInvalidbooleanWhether this date is invalid per minValue/maxValue constraints
isPressedbooleanWhether the day cell pressable is in a pressed state
isRangeStartbooleanFirst day of the highlighted range (range calendar only)
isRangeEndbooleanLast day of the highlighted range (range calendar only)
isRangeFilledbooleanWhether the range spans more than one day (range calendar only)
isRangeMiddlebooleanStrictly inside the range, not start or end (range calendar only)
isRangeMiddleRowStartbooleanRange middle cell at the start of a row (range calendar only)
isRangeMiddleRowEndbooleanRange middle cell at the end of a row (range calendar only)

Calendar.CellBody

proptypedefaultdescription
childrenReact.ReactNode-Body content (typically CellLabel and optional CellIndicator)
cellRenderPropsCalendarCellRenderProps-Render props from Calendar.Cell's children callback; drives data-* selectors
isAnimatedStyleActivebooleantrueWhether animated scale styles are applied; set false for custom logic
classNamestring-Additional CSS classes for the cell body container
animationCalendarCellBodyAnimation-Press scale animation configuration
...ViewPropsViewProps-All standard React Native View props are supported

Data Attributes

attributevaluesdescription
data-todaybooleanWhether the date is today
data-outside-monthbooleanWhether the date is outside the visible month
data-unavailablebooleanWhether the date is unavailable
data-disabledbooleanWhether the date is disabled
data-focusedbooleanWhether the date is focused
data-invalidbooleanWhether the date is invalid
data-selectedbooleanWhether the date is selected
data-pressedbooleanWhether the cell is pressed
data-range-startbooleanFirst day of a range (range calendar only)
data-range-endbooleanLast day of a range (range calendar only)
data-range-filledbooleanRange spans multiple days (range calendar only)
data-range-middlebooleanInside the range, not start/end (range only)
data-range-middle-row-startbooleanRange middle at row start (range calendar only)
data-range-middle-row-endbooleanRange middle at row end (range calendar only)
data-disabled-not-outside-monthbooleanDisabled but within the visible month

CalendarCellBodyAnimation

Animation configuration for Calendar.CellBody press feedback. Can be:

  • false or "disabled": Disable press animation
  • undefined: Use default animation
  • object: Custom animation configuration
proptypedefaultdescription
scale.value[number, number][1, 0.9]Scale values [unpressed, pressed]
scale.timingConfigWithTimingConfig{ duration: 120 }Animation timing configuration

Calendar.CellLabel

proptypedefaultdescription
childrenReact.ReactNode-Label text (usually the day number)
cellRenderPropsCalendarCellRenderProps-Render props from Calendar.Cell's children callback; drives data-* selectors
classNamestring-Additional CSS classes for the label text
...TextPropsTextProps-All standard React Native Text props are supported

Data Attributes

Same data attributes as Calendar.CellBody. See above.

Calendar.CellIndicator

proptypedefaultdescription
cellRenderPropsCalendarCellRenderProps-Render props from Calendar.Cell's children callback; drives data-* selectors
classNamestring-Additional CSS classes for the indicator dot container
...ViewPropsViewProps-All standard React Native View props are supported

Data Attributes

Same data attributes as Calendar.CellBody. See above.

Calendar.YearPickerTrigger

proptypedefaultdescription
childrenReact.ReactNode | ((values: YearPickerTriggerRenderProps) => React.ReactNode)-Trigger content or render function
...PressablePropsPressableProps-All standard React Native Pressable props are supported

YearPickerTriggerRenderProps

propertytypedescription
isOpenbooleanWhether the year picker is open
monthYearstringFormatted month/year heading string
toggle() => voidToggle the year picker open state

Calendar.YearPickerTriggerHeading

proptypedefaultdescription
childrenReact.ReactNode | ((values: YearPickerTriggerRenderProps) => React.ReactNode)-Heading text or render function; auto-computed when omitted
...TextPropsTextProps-All standard React Native Text props are supported

Calendar.YearPickerTriggerIndicator

proptypedefaultdescription
childrenReact.ReactNode | ((values: YearPickerTriggerRenderProps) => React.ReactNode)-Custom indicator content or render function
iconProps{ size?: number; color?: string }-Overrides for the default chevron icon
isAnimatedStyleActivebooleantrueWhether animated rotation styles are applied
animationYearPickerIndicatorAnimation-Rotation animation configuration
...ViewPropsViewProps-All standard React Native View props are supported

YearPickerIndicatorAnimation

Animation configuration for the year picker trigger chevron rotation. Can be:

  • false or "disabled": Disable rotation animation
  • undefined: Use default animation
  • object: Custom animation configuration
proptypedefaultdescription
rotation.value[number, number][0, 90]Rotation degrees [closed, open]
rotation.springConfigWithSpringConfigDefault springSpring configuration for the rotation

Calendar.YearPickerGrid

proptypedefaultdescription
childrenReact.ReactNode-Grid content (YearPickerGridBody)
isAnimatedStyleActivebooleantrueWhether animated opacity styles are applied
animationYearPickerGridAnimation-Opacity animation configuration
...ViewPropsViewProps-All standard React Native View props are supported

YearPickerGridAnimation

Animation configuration for the year picker grid overlay. Can be:

  • false or "disabled": Disable opacity animation
  • undefined: Use default animation
  • object: Custom animation configuration
proptypedefaultdescription
opacity.value[number, number][0, 1]Opacity values [closed, open]
opacity.timingConfigWithTimingConfig{ duration: 200 }Timing configuration for the opacity

Calendar.YearPickerGridBody

proptypedefaultdescription
children(values: YearPickerCellRenderProps) => React.ReactNode-Render function called for each year
...FlatListPropsFlatListProps<number>-FlatList props except data, renderItem, keyExtractor, numColumns, and columnWrapperStyle

YearPickerCellRenderProps

propertytypedescription
yearnumberThe year number
formattedYearstringLocale-formatted year string
isSelectedbooleanWhether this year matches the selection
isCurrentYearbooleanWhether this year is the current year
isOpenbooleanWhether the year picker is open
selectYear() => voidSelect this year and close the picker

Calendar.YearPickerCell

proptypedefaultdescription
yearnumber-The year this cell represents (required)
isSelectedboolean-Whether this year is selected (required)
childrenReact.ReactNode | ((values: YearPickerCellRenderProps) => React.ReactNode)-Custom cell content or render function
...PressablePropsPressableProps-All standard React Native Pressable props are supported

Hooks

useCalendar

Hook to access the calendar state context. Must be used within a Calendar component.

import { useCalendar } from 'heroui-native-pro';

const state = useCalendar();

Returns: CalendarState

propertytypedescription
valueCalendarDate | nullCurrently selected date
setValue(value: CalendarDate | null) => voidSet the selected date
visibleRangeRangeValue<CalendarDate>The date range currently visible in the calendar
focusedDateCalendarDateCurrently focused date
setFocusedDate(value: CalendarDate) => voidSet the focused date
isDisabledbooleanWhether the calendar is disabled
isReadOnlybooleanWhether the calendar is read-only
isValueInvalidbooleanWhether the current value is invalid
timeZonestringTime zone of displayed dates
minValueDateValue | null | undefinedMinimum allowed date
maxValueDateValue | null | undefinedMaximum allowed date
focusNextPage() => voidNavigate to the next month
focusPreviousPage() => voidNavigate to the previous month
selectFocusedDate() => voidSelect the currently focused date
selectDate(date: CalendarDate) => voidSelect a specific date
isSelected(date: CalendarDate) => booleanCheck if a date is selected
isInvalid(date: CalendarDate) => booleanCheck if a date is invalid
isCellDisabled(date: CalendarDate) => booleanCheck if a date cell is disabled
isCellUnavailable(date: CalendarDate) => booleanCheck if a date cell is unavailable
isCellFocused(date: CalendarDate) => booleanCheck if a date cell is focused
getDatesInWeek(weekIndex: number, startDate?: CalendarDate) => Array<CalendarDate | null>Get dates for a week row

On this page