Beta Preview

Calendar

Calendars display a grid of days in one or more months and allow users to select a single date.

Event date, September 2025

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
 
pageBehavior 
firstDayOfWeek 
isDisabled 
import {Calendar} from '@react-spectrum/s2';

<Calendar aria-label="Event date" />

Value

Use the value or defaultValue prop to set the date value, 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 2020

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

Selected date: 2/3/2020

import {parseDate, getLocalTimeZone} from '@internationalized/date';
import {Calendar} from '@react-spectrum/s2';
import {useState} from 'react';

function Example() {
  let [date, setDate] = useState(parseDate('2020-02-03'));
  
  return (
    <>
      <Calendar
        value={date}
        onChange={setDate}
      />
      <p>Selected date: {date.toDate(getLocalTimeZone()).toLocaleDateString()}</p>
    </>
  );
}

International calendars

By default, Calendar 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
Locale
Calendar
import {Provider, Calendar} from '@react-spectrum/s2';
import {parseDate} from '@internationalized/date';

<Provider locale="hi-IN-u-ca-indian">
  <Calendar defaultValue={parseDate('2025-02-03')} />
</Provider>

Custom calendar systems

Calendar 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

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 {Calendar} from '@react-spectrum/s2';

export default (
  <Calendar
    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. For custom validation rules, set the isInvalid and errorMessage props.

Appointment date, September 2025

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
isInvalid 
 
import {isWeekend, today, getLocalTimeZone} from '@internationalized/date';
import {useLocale} from 'react-aria';
import {Calendar} from '@react-spectrum/s2';

function Example(props) {
  let {locale} = useLocale();
  let now = today(getLocalTimeZone());
  let disabledRanges = [
    [now, now.add({ days: 5 })],
    [now.add({ days: 14 }), now.add({ days: 16 })],
    [now.add({ days: 23 }), now.add({ days: 24 })]
  ];

  return (
    <Calendar
      {...props}
      aria-label="Appointment date"
      minValue={today(getLocalTimeZone())}
      isDateUnavailable={date => (
        isWeekend(date, locale) ||
        disabledRanges.some((interval) =>
          date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0
        )
      )} />
  );
}

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

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 {Calendar, 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>
      <Calendar
        focusedValue={focusedDate}
        onFocusChange={setFocusedDate}
      />
    </div>
  );
}

API

NameTypeDefault
visibleMonthsnumberDefault: 1
The number of months to display at once.
createCalendar(identifier: ) => 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.
isDateUnavailable(date: ) => booleanDefault:
Callback that is called for each date of the calendar. If it returns true, then the date is unavailable.
isDisabledbooleanDefault: false
Whether the calendar is disabled.
isReadOnlybooleanDefault: false
Whether the calendar value is immutable.
focusedValuenullDefault:
Controls the currently focused date within the calendar.
defaultFocusedValuenullDefault:
The date that is focused when the calendar first mounts (uncountrolled).
pageBehaviorDefault: 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<>Default:
The children of the component. A function may be provided to alter the children based on component state.
stylesDefault:
Spectrum-defined styles, returned by the style() macro.
valuenullDefault:
The current value (controlled).
defaultValuenullDefault:
The default value (uncontrolled).
onChange(value: <>) => voidDefault:
Handler that is called when the value changes.