A date range calendar for selecting start and end dates with month navigation, locale support, and customizable day cells.
import { RangeCalendar } from 'heroui-native-pro' ;
< RangeCalendar >
< RangeCalendar.Header >
< RangeCalendar.Heading />
< RangeCalendar.NavButton slot = "previous" />
< RangeCalendar.NavButton slot = "next" />
</ RangeCalendar.Header >
< RangeCalendar.Grid >
< RangeCalendar.GridHeader >
{( day ) => < RangeCalendar.HeaderCell day = {day} />}
</ RangeCalendar.GridHeader >
< RangeCalendar.GridBody >
{( date ) => < RangeCalendar.Cell date = {date} />}
</ RangeCalendar.GridBody >
</ RangeCalendar.Grid >
</ RangeCalendar >
< RangeCalendar >
< RangeCalendar.Header >
< RangeCalendar.YearPickerTrigger >
< RangeCalendar.YearPickerTriggerHeading />
< RangeCalendar.YearPickerTriggerIndicator />
</ RangeCalendar.YearPickerTrigger >
< RangeCalendar.NavButton slot = "previous" />
< RangeCalendar.NavButton slot = "next" />
</ RangeCalendar.Header >
< RangeCalendar.Grid >
< RangeCalendar.GridHeader >
{( day ) => < RangeCalendar.HeaderCell day = {day} />}
</ RangeCalendar.GridHeader >
< RangeCalendar.GridBody >
{( date ) => < RangeCalendar.Cell date = {date} />}
</ RangeCalendar.GridBody >
</ RangeCalendar.Grid >
< RangeCalendar.YearPickerGrid >
< RangeCalendar.YearPickerGridBody >
{( renderProps ) => (
< RangeCalendar.YearPickerCell
year = {renderProps.year}
isSelected = {renderProps.isSelected}
/>
)}
</ RangeCalendar.YearPickerGridBody >
</ RangeCalendar.YearPickerGrid >
</ RangeCalendar >
RangeCalendar : Root container that manages date range selection state, locale, and animation settings. Supports controlled and uncontrolled modes with min/max constraints and date unavailability filtering.
RangeCalendar.Header : Toolbar row for navigation controls and the month/year title.
RangeCalendar.Heading : Month/year label text. The primitive computes the heading string automatically when children are omitted.
RangeCalendar.NavButton : Previous or next month navigation button. Renders a default chevron icon using the theme accent color; override via iconProps or pass custom children.
RangeCalendar.Grid : Month grid container that provides internal grid context to the header and body.
RangeCalendar.GridHeader : Weekday labels row. Requires a render function (day: string) => ReactElement as children.
RangeCalendar.GridBody : Day cells matrix. Requires a render function (date: CalendarDate) => ReactElement as children.
RangeCalendar.HeaderCell : Single weekday header cell. Stringifiable children are wrapped in HeaderCellLabel; pass day when omitting children.
RangeCalendar.HeaderCellLabel : Text slot for a weekday header cell label.
RangeCalendar.Cell : Selectable day cell with range highlight strip styling. By default renders CellBody with CellLabel inside. Pass a render function as children to customize the cell content.
RangeCalendar.CellBody : Inner rounded region of a day cell with press scale animation. Accent background is applied on range start/end cells. Pass cellRenderProps for data attribute selectors.
RangeCalendar.CellLabel : Day number label. Uses data-range-start and data-range-end for accent foreground color. Pass cellRenderProps for data attribute selectors.
RangeCalendar.CellIndicator : Dot marker under a day cell (e.g. for events). Pass cellRenderProps for data-selected styling.
RangeCalendar.YearPickerTrigger : Pressable trigger that replaces Heading to toggle the year picker overlay.
RangeCalendar.YearPickerTriggerHeading : Month/year label text inside the year picker trigger.
RangeCalendar.YearPickerTriggerIndicator : Animated chevron icon indicating the year picker open state.
RangeCalendar.YearPickerGrid : Overlay container positioned over the month grid when the year picker is open.
RangeCalendar.YearPickerGridBody : Scrollable list of year cells inside the year picker grid.
RangeCalendar.YearPickerCell : Pressable year cell that selects a year and closes the picker.
The RangeCalendar uses the same compound structure as Calendar. Users select a start and end date by tapping two different days.
< RangeCalendar
accessibilityLabel = "Trip dates"
defaultValue = {{
start: parseDate ( '2026-04-01' ),
end: parseDate ( '2026-04-07' ),
}}
>
< RangeCalendar.Header >
< RangeCalendar.Heading />
< RangeCalendar.NavButton slot = "previous" />
< RangeCalendar.NavButton slot = "next" />
</ RangeCalendar.Header >
< RangeCalendar.Grid >
< RangeCalendar.GridHeader >
{( day ) => < RangeCalendar.HeaderCell day = {day} />}
</ RangeCalendar.GridHeader >
< RangeCalendar.GridBody >
{( date ) => < RangeCalendar.Cell date = {date} />}
</ RangeCalendar.GridBody >
</ RangeCalendar.Grid >
</ RangeCalendar >
Use value and onChange to control the selected range externally.
const [ range , setRange ] = useState ({
start: parseDate ( '2026-04-01' ),
end: parseDate ( '2026-04-07' ),
});
< RangeCalendar value = {range} onChange = {setRange}>
< RangeCalendar.Header >
< RangeCalendar.Heading />
< RangeCalendar.NavButton slot = "previous" />
< RangeCalendar.NavButton slot = "next" />
</ RangeCalendar.Header >
< RangeCalendar.Grid >
< RangeCalendar.GridHeader >
{( day ) => < RangeCalendar.HeaderCell day = {day} />}
</ RangeCalendar.GridHeader >
< RangeCalendar.GridBody >
{( date ) => < RangeCalendar.Cell date = {date} />}
</ RangeCalendar.GridBody >
</ RangeCalendar.Grid >
</ RangeCalendar >;
Restrict navigation and selection to a date range using minValue and maxValue.
const now = today ( getLocalTimeZone ());
< RangeCalendar minValue = {now} maxValue = {now. add ({ months: 2 })}>
< RangeCalendar.Header >
< RangeCalendar.Heading />
< RangeCalendar.NavButton slot = "previous" />
< RangeCalendar.NavButton slot = "next" />
</ RangeCalendar.Header >
< RangeCalendar.Grid >
< RangeCalendar.GridHeader >
{( day ) => < RangeCalendar.HeaderCell day = {day} />}
</ RangeCalendar.GridHeader >
< RangeCalendar.GridBody >
{( date ) => < RangeCalendar.Cell date = {date} />}
</ RangeCalendar.GridBody >
</ RangeCalendar.Grid >
</ RangeCalendar >;
Enable allowsNonContiguousRanges to allow ranges that span across unavailable dates.
const isDateUnavailable = ( date : DateValue ) => {
return blockedRanges. some (
([ start , end ]) => date. compare (start) >= 0 && date. compare (end) <= 0
);
};
< RangeCalendar allowsNonContiguousRanges isDateUnavailable = {isDateUnavailable}>
< RangeCalendar.Header >
< RangeCalendar.Heading />
< RangeCalendar.NavButton slot = "previous" />
< RangeCalendar.NavButton slot = "next" />
</ RangeCalendar.Header >
< RangeCalendar.Grid >
< RangeCalendar.GridHeader >
{( day ) => < RangeCalendar.HeaderCell >{day}</ RangeCalendar.HeaderCell >}
</ RangeCalendar.GridHeader >
< RangeCalendar.GridBody >
{( date ) => < RangeCalendar.Cell date = {date} />}
</ RangeCalendar.GridBody >
</ RangeCalendar.Grid >
</ RangeCalendar >;
Add a year picker overlay by replacing Heading with YearPickerTrigger and adding a YearPickerGrid inside the root.
< RangeCalendar >
< RangeCalendar.Header >
< RangeCalendar.YearPickerTrigger >
< RangeCalendar.YearPickerTriggerHeading />
< RangeCalendar.YearPickerTriggerIndicator />
</ RangeCalendar.YearPickerTrigger >
< RangeCalendar.NavButton slot = "previous" />
< RangeCalendar.NavButton slot = "next" />
</ RangeCalendar.Header >
< RangeCalendar.Grid >
< RangeCalendar.GridHeader >
{( day ) => < RangeCalendar.HeaderCell day = {day} />}
</ RangeCalendar.GridHeader >
< RangeCalendar.GridBody >
{( date ) => < RangeCalendar.Cell date = {date} />}
</ RangeCalendar.GridBody >
</ RangeCalendar.Grid >
< RangeCalendar.YearPickerGrid >
< RangeCalendar.YearPickerGridBody >
{({ year , isSelected }) => (
< RangeCalendar.YearPickerCell year = {year} isSelected = {isSelected} />
)}
</ RangeCalendar.YearPickerGridBody >
</ RangeCalendar.YearPickerGrid >
</ RangeCalendar >
Disable the entire calendar and all navigation controls.
< RangeCalendar isDisabled >
< RangeCalendar.Header >
< RangeCalendar.Heading />
< RangeCalendar.NavButton slot = "previous" />
< RangeCalendar.NavButton slot = "next" />
</ RangeCalendar.Header >
< RangeCalendar.Grid >
< RangeCalendar.GridHeader >
{( day ) => < RangeCalendar.HeaderCell day = {day} />}
</ RangeCalendar.GridHeader >
< RangeCalendar.GridBody >
{( date ) => < RangeCalendar.Cell date = {date} />}
</ RangeCalendar.GridBody >
</ RangeCalendar.Grid >
</ RangeCalendar >
import {
parseDate,
today,
getLocalTimeZone,
type DateValue,
} from '@internationalized/date' ;
import { RangeCalendar } from 'heroui-native-pro' ;
import { useState } from 'react' ;
import { View } from 'react-native' ;
export default function RangeCalendarExample () {
const now = today ( getLocalTimeZone ());
const blockedRanges = [
[now. add ({ days: 2 }), now. add ({ days: 5 })],
[now. add ({ days: 12 }), now. add ({ days: 13 })],
] as const ;
const isDateUnavailable = ( date : DateValue ) => {
return blockedRanges. some (
([ start , end ]) => date. compare (start) >= 0 && date. compare (end) <= 0
);
};
return (
< View className = "flex-1 justify-center px-5" >
< RangeCalendar
allowsNonContiguousRanges
accessibilityLabel = "Trip dates"
isDateUnavailable = {isDateUnavailable}
defaultValue = {{
start: parseDate ( '2026-04-01' ),
end: parseDate ( '2026-04-07' ),
}}
>
< RangeCalendar.Header >
< RangeCalendar.Heading />
< RangeCalendar.NavButton slot = "previous" />
< RangeCalendar.NavButton slot = "next" />
</ RangeCalendar.Header >
< RangeCalendar.Grid >
< RangeCalendar.GridHeader >
{( day ) => (
< RangeCalendar.HeaderCell >{day}</ RangeCalendar.HeaderCell >
)}
</ RangeCalendar.GridHeader >
< RangeCalendar.GridBody >
{( date ) => < RangeCalendar.Cell date = {date} />}
</ RangeCalendar.GridBody >
</ RangeCalendar.Grid >
</ RangeCalendar >
</ View >
);
}
prop type default description childrenReact.ReactNode | ((props: { state: RangeCalendarState }) => React.ReactNode)- Calendar content or render function receiving range calendar state valueRangeValue<DateValue> | null- Controlled selected date range defaultValueRangeValue<DateValue> | null- Default selected date range 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 allowsNonContiguousRangesboolean- Allow ranges that span across unavailable dates 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: RangeValue<MappedDateValue<DateValue>>) => void- Handler called when the selected range changes onYearPickerOpenChange(isOpen: boolean) => void- Handler called when the year picker open state changes ...ViewPropsViewProps- All standard React Native View props are supported
property type description startDateValueThe start date of the range endDateValueThe end date of the range
Animation configuration for the RangeCalendar root. Can be:
"disable-all": Disable all animations including children (cascades down)
undefined: Use default animations
prop type default description 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
prop type default description 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
prop type default description 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 iconPropsRangeCalendarNavButtonIconProps- Overrides for the built-in chevron; ignored with custom children ...PressablePropsPressableProps- All standard React Native Pressable props are supported
prop type default description sizenumber18Icon size in logical pixels colorstringTheme accent Icon stroke/fill color
prop type default description 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
prop type default description 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
prop type default description 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
prop type default description 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
prop type default description childrenReact.ReactNode- Weekday label text classNamestring- Additional CSS classes for the label text ...TextPropsTextProps- All standard React Native Text props are supported
prop type default description 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
Render props received by the RangeCalendar.Cell children render function.
property type description 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 isRangeEndbooleanLast day of the highlighted range isRangeFilledbooleanWhether the range spans more than one day isRangeMiddlebooleanStrictly inside the range, not start or end isRangeMiddleRowStartbooleanRange middle cell at the start of a row isRangeMiddleRowEndbooleanRange middle cell at the end of a row
prop type default description childrenReact.ReactNode- Body content (typically CellLabel and optional CellIndicator) cellRenderPropsCalendarCellRenderProps- Render props from RangeCalendar.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
attribute values description 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 the selected range data-range-endbooleanLast day of the selected range data-range-filledbooleanRange spans multiple days data-range-middlebooleanInside the range, not start or end data-range-middle-row-startbooleanRange middle at the start of a row data-range-middle-row-endbooleanRange middle at the end of a row data-disabled-not-outside-monthbooleanDisabled but within the visible month
Animation configuration for RangeCalendar.CellBody press feedback. Can be:
false or "disabled": Disable press animation
undefined: Use default animation
object: Custom animation configuration
prop type default description scale.value[number, number][1, 0.9]Scale values [unpressed, pressed] scale.timingConfigWithTimingConfig{ duration: 120 }Animation timing configuration
prop type default description childrenReact.ReactNode- Label text (usually the day number) cellRenderPropsCalendarCellRenderProps- Render props from RangeCalendar.Cell's children callback; drives data-* selectors classNamestring- Additional CSS classes for the label text ...TextPropsTextProps- All standard React Native Text props are supported
Same data attributes as RangeCalendar.CellBody. See above.
prop type default description cellRenderPropsCalendarCellRenderProps- Render props from RangeCalendar.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
Same data attributes as RangeCalendar.CellBody. See above.
prop type default description childrenReact.ReactNode | ((values: YearPickerTriggerRenderProps) => React.ReactNode)- Trigger content or render function ...PressablePropsPressableProps- All standard React Native Pressable props are supported
property type description isOpenbooleanWhether the year picker is open monthYearstringFormatted month/year heading string toggle() => voidToggle the year picker open state
prop type default description childrenReact.ReactNode | ((values: YearPickerTriggerRenderProps) => React.ReactNode)- Heading text or render function; auto-computed when omitted ...TextPropsTextProps- All standard React Native Text props are supported
prop type default description 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
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
prop type default description rotation.value[number, number][0, 90]Rotation degrees [closed, open] rotation.springConfigWithSpringConfigDefault spring Spring configuration for the rotation
prop type default description childrenReact.ReactNode- Grid content (YearPickerGridBody) isAnimatedStyleActivebooleantrueWhether animated opacity styles are applied animationYearPickerGridAnimation- Opacity animation configuration ...ViewPropsViewProps- All standard React Native View props are supported
Animation configuration for the year picker grid overlay. Can be:
false or "disabled": Disable opacity animation
undefined: Use default animation
object: Custom animation configuration
prop type default description opacity.value[number, number][0, 1]Opacity values [closed, open] opacity.timingConfigWithTimingConfig{ duration: 200 }Timing configuration for the opacity
prop type default description children(values: YearPickerCellRenderProps) => React.ReactNode- Render function called for each year ...FlatListPropsFlatListProps<number>- FlatList props except data, renderItem, keyExtractor, numColumns, and columnWrapperStyle
property type description 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
prop type default description 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
Hook to access the range calendar state context. Must be used within a RangeCalendar component.
import { useRangeCalendar } from 'heroui-native-pro' ;
const state = useRangeCalendar ();
property type description valueRangeValue<DateValue> | nullCurrently selected date range setValue(value: RangeValue<DateValue> | null) => voidSet the selected date range highlightedRangeRangeValue<CalendarDate> | nullThe currently highlighted range (committed or preview) anchorDateCalendarDate | nullAnchor date the user clicked to begin range selection setAnchorDate(date: CalendarDate | null) => voidSet the anchor date isDraggingbooleanWhether the user is currently dragging over the calendar setDragging(isDragging: boolean) => voidSet the dragging state highlightDate(date: CalendarDate) => voidHighlight a date during range selection clearSelection() => voidClear the current selection 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