RangeCalendar
RangeCalendars display a grid of days in one or more months and allow users to select a contiguous range of dates.
September 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 |
firstDayOfWeek
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 '@react-spectrum/s2';
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 <Provider>
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.
September 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 |
import type {AnyCalendarDate} from '@internationalized/date';
import {CalendarDate, startOfWeek, toCalendar, GregorianCalendar} from '@internationalized/date';
import {RangeCalendar} from '@react-spectrum/s2';
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.
September 2025
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 |
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, ActionButton} from '@react-spectrum/s2';
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 style={{display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8}}>
<ActionButton onPress={() => setFocusedDate(today(getLocalTimeZone()))}>
Today
</ActionButton>
<RangeCalendar
focusedValue={focusedDate}
onFocusChange={setFocusedDate}
/>
</div>
);
}
API
Name | Type | Default |
---|---|---|
visibleMonths | number | Default: 1
|
The number of months to display at once. | ||
createCalendar |
| Default: — |
A function to create a new Calendar
object for a given calendar identifier. If not provided, the createCalendar function
from @internationalized/date will be used. | ||
allowsNonContiguousRanges | boolean | Default: — |
When combined with isDateUnavailable , determines whether non-contiguous ranges,
i.e. ranges containing unavailable dates, may be selected. | ||
isDateUnavailable |
| Default: — |
Callback that is called for each date of the calendar. If it returns true, then the date is unavailable. | ||
isDisabled | boolean | Default: false
|
Whether the calendar is disabled. | ||
isReadOnly | boolean | Default: false
|
Whether the calendar value is immutable. | ||
focusedValue | DateValue | null | Default: — |
Controls the currently focused date within the calendar. | ||
defaultFocusedValue | DateValue | null | Default: — |
The date that is focused when the calendar first mounts (uncountrolled). | ||
pageBehavior | PageBehavior | Default: visible
|
Controls the behavior of paging. Pagination either works by advancing the visible page by visibleDuration (default) or one unit of visibleDuration. | ||
firstDayOfWeek | 'sun'
| 'mon'
| 'tue'
| 'wed'
| 'thu'
| 'fri'
| 'sat' | Default: — |
The day that starts the week. | ||
selectionAlignment | 'start'
| 'center'
| 'end' | Default: 'center'
|
Determines the alignment of the visible months on initial render based on the current selection or current date if there is no selection. | ||
children | ChildrenOrFunction | Default: — |
The children of the component. A function may be provided to alter the children based on component state. | ||
styles | StylesProp | Default: — |
Spectrum-defined styles, returned by the style() macro. | ||
value | RangeValue | Default: — |
The current value (controlled). | ||
defaultValue | RangeValue | Default: — |
The default value (uncontrolled). | ||
onChange |
| Default: — |
Handler that is called when the value changes. | ||