RangeCalendar
A range calendar displays one or more date grids and allows users to select a contiguous range of dates.
October 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
Value
Use the value
or defaultValue
prop to set the selected date range, using objects in the @internationalized/date package. This library supports parsing date strings in multiple formats, manipulation across international calendar systems, time zones, etc.
February 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 1 |
Selected range: February 3 – 12, 2025
import {parseDate, getLocalTimeZone} from '@internationalized/date';
import {useDateFormatter} from 'react-aria';
import {RangeCalendar} from './RangeCalendar';
import {useState} from 'react';
function Example() {
let [range, setRange] = useState({
start: parseDate('2025-02-03'),
end: parseDate('2025-02-12')
});
let formatter = useDateFormatter({ dateStyle: 'long' });
return (
<>
<RangeCalendar
value={range}
onChange={setRange}
/>
<p>Selected range: {formatter.formatRange(
range.start.toDate(getLocalTimeZone()),
range.end.toDate(getLocalTimeZone())
)}</p>
</>
);
}
International calendars
By default, RangeCalendar
displays the value using the calendar system for the user's locale. Use <I18nProvider>
to override the calendar system by setting the Unicode calendar locale extension. The onChange
event always receives a date in the same calendar as the value
or defaultValue
(Gregorian if no value is provided), regardless of the displayed locale.
शक 1946 माघ
र | सो | मं | बु | गु | शु | श |
---|---|---|---|---|---|---|
29 | 30 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 1 | 2 | 3 |
Custom calendar systems
RangeCalendar
also supports custom calendar systems that implement custom business rules, for example a fiscal year calendar that follows a 4-5-4 format, where month ranges don't follow the usual Gregorian calendar. See the @internationalized/date docs for an example implementation.
October 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
import type {AnyCalendarDate} from '@internationalized/date';
import {CalendarDate, startOfWeek, toCalendar, GregorianCalendar} from '@internationalized/date';
import {RangeCalendar} from './RangeCalendar';
export default (
<RangeCalendar
firstDayOfWeek="sun"
createCalendar={() => new Custom454()} />
);
// See @internationalized/date docs linked above.
Validation
Use the minValue
and maxValue
props to set the valid date range. The isDateUnavailable
callback prevents certain dates from being selected. Use allowsNonContiguousRanges
to allow selecting ranges containing unavailable dates. For custom validation rules, set the isInvalid
prop and the errorMessage
slot.
October 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
Display options
Set the visibleDuration
prop and render multiple CalendarGrid
elements to display more than one month at a time. The pageBehavior
prop controls whether pagination advances by a single month or multiple. The firstDayOfWeek
prop overrides the locale-specified first day of the week.
October 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
November 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 1 | 2 | 3 | 4 | 5 | 6 |
firstDayOfWeek
Controlling the focused date
Use the focusedValue
or defaultFocusedValue
prop to control which date is focused. This controls which month is visible. The onFocusChange
event is called when a date is focused by the user.
July 2021
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
import {RangeCalendar} from './RangeCalendar';
import {Button} from './Button';
import {CalendarDate, today, getLocalTimeZone} from '@internationalized/date';
import {useState} from 'react';
function Example() {
let defaultDate = new CalendarDate(2021, 7, 1);
let [focusedDate, setFocusedDate] = useState(defaultDate);
return (
<div>
<Button
style={{marginBottom: 20}}
onPress={() => setFocusedDate(today(getLocalTimeZone()))}>
Today
</Button>
<RangeCalendar
focusedValue={focusedDate}
onFocusChange={setFocusedDate}
/>
</div>
);
}
Month and year pickers
You can also control the focused date via CalendarStateContext
. This example shows month and year dropdown components that work inside any <RangeCalendar>
.
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
import {RangeCalendar, CalendarGrid, CalendarCell} from 'react-aria-components';
import {MonthDropdown} from './MonthDropdown';
import {YearDropdown} from './YearDropdown';
import {Button} from './Button';
<RangeCalendar>
<header style={{display: 'flex', gap: 4}}>
<Button slot="previous">◀</Button>
<MonthDropdown />
<YearDropdown />
<Button slot="next">▶</Button>
</header>
<CalendarGrid>
{(date) => <CalendarCell date={date} />}
</CalendarGrid>
</RangeCalendar>