Calendar 
A calendar displays one or more date grids and allows users to select a single date.
Theme 
Indigo Blue Cyan Turquoise Green Yellow Orange Red Pink Purple 
October 2025 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
Example 
Calendar.tsx 
Calendar.css 
Example 
Calendar.tsx 
Calendar.css 
import  {Calendar} from  './Calendar' ;
<Calendar  />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: Monday, February 3, 2020
import  {parseDate , getLocalTimeZone } from  '@internationalized/date' ;
import  {useDateFormatter } from  'react-aria' ;
import  {Calendar} from  './Calendar' ;
import  {useState } from  'react' ;
function  Example() {
  let  [date , setDate ] = useState (parseDate ('2020-02-03' ));
  let  formatter  = useDateFormatter ({ dateStyle : 'full'  });
  
return  (
    <>
      <Calendar 
        value ={date }
        onChange ={setDate }
       />
      <p >Selected date: {formatter .format (date .toDate (getLocalTimeZone ()))}</p >
    </>
  );
}
Expand code 
International calendars 
By default, Calendar 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
Locale 
Amharic (Ethiopia) Arabic (Algeria) Arabic (Egypt) Arabic (Saudi Arabia) Arabic (United Arab Emirates) Bulgarian (Bulgaria) Chinese (China) Chinese (Taiwan) Croatian (Croatia) Czech (Czechia) Danish (Denmark) Dutch (Netherlands) English (United Kingdom) English (United States) Estonian (Estonia) Finnish (Finland) French (Canada) French (France) German (Germany) Greek (Greece) Hebrew (Israel) Hindi (India) Hungarian (Hungary) Italian (Italy) Japanese (Japan) Korean (South Korea) Latvian (Latvia) Lithuanian (Lithuania) Norwegian Bokmål (Norway) Persian (Afghanistan) Polish (Poland) Portuguese (Brazil) Romanian (Romania) Russian (Russia) Serbian (SP) Slovak (Slovakia) Slovenian (Slovenia) Spanish (Spain) Swedish (Sweden) Thai (Thailand) Turkish (Türkiye) Ukrainian (Ukraine) 
Calendar 
Gregorian Indian Japanese Buddhist Taiwan Persian Islamic (Umm al-Qura) Islamic Civil Islamic Tabular Hebrew Coptic Ethiopic Ethiopic (Amete Alem) 
import  {I18nProvider} from  'react-aria-components' ;
import  {parseDate } from  '@internationalized/date' ;
import  {Calendar} from  './Calendar' ;
I18nProvider  locale ="hi-IN-u-ca-indian" >
  <Calendar  defaultValue ={parseDate ('2025-02-03' )} />
</I18nProvider >
Expand code 
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.
October 2025 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  {Calendar} from  './Calendar' ;
export  default  (
  <Calendar 
    firstDayOfWeek ="sun" 
    createCalendar ={() => new  Custom454()} />
 );
// See @internationalized/date docs linked above. 
  weekPattern  = [4 , 5 , 4 , 4 , 5 , 4 , 4 , 5 , 4 , 4 , 5 , 4 ];
  getDaysInMonth (date ) {
    return  this .weekPattern [date .month  - 1 ] * 7 ;
  }
  fromJulianDay (jd : number): CalendarDate {
    let  gregorian  = super .fromJulianDay (jd );
    let  monthStart  = startOfWeek (new  CalendarDate(gregorian .year , 1 , 1 ), 'en' );
    for  (let  months  = 0 ; months  < this .weekPattern .length ; months ++) {
      let  weeksInMonth  = this .weekPattern [months ];
      let  monthEnd  = monthStart .add ({weeks : weeksInMonth });
      if  (monthEnd .compare (gregorian ) > 0 ) {
        let  days  = gregorian .compare (monthStart );
        return  new  CalendarDate(this , monthStart .year , months  + 1 , days  + 1 );
      }
      monthStart  = monthEnd ;
    }
    throw  Error('Date is not in any month somehow!' );
  }
  toJulianDay (date : AnyCalendarDate): number {
    let  monthStart  = startOfWeek (new  CalendarDate(date .year , 1 , 1 ), 'en' );
    for  (let  month  = 1 ; month  < date .month ; month ++) {
      monthStart  = monthStart .add ({weeks : this .weekPattern [month  - 1 ]});
    }
    let  gregorian  = monthStart .add ({days : date .day  - 1 });
    return  super .toJulianDay (gregorian );
  }
  getFormattableMonth (date ) {
    let  gregorian  = toCalendar (date , new  GregorianCalendar());
    return  gregorian .set ({month : date .month , day : 1 });
  }
  isEqual (other ) {
    return  other  instanceof  Custom454;
  }
}
Expand code 
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 prop and the errorMessage slot.
Appointment date, October 2025 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  {isWeekend , today , getLocalTimeZone } from  '@internationalized/date' ;
import  {useLocale } from  'react-aria' ;
import  {Calendar} from  './Calendar' ;
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 
        )
      )} />
   );
}
Expand code 
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.
Appointment date, October to November 2025 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
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
pageBehavior   single visible 
 firstDayOfWeek The day that starts the week. 
'sun' 
  | 'mon' 
  | 'tue' 
  | 'wed' 
  | 'thu' 
  | 'fri' 
  | 'sat'  Default sun mon tue wed thu fri sat 
import  {Calendar, Heading} from  'react-aria-components' ;
import  {CalendarGrid, CalendarCell} from  './Calendar' ;
import  {Button} from  './Button' ;
import  {useDateFormatter } from  'react-aria' ;
import  {ChevronLeft, ChevronRight} from  'lucide-react' ;
// TODO: move this into the starter example. 
function  Example(props ) {
  let  monthFormatter  = useDateFormatter ({
    month : 'long' ,
    year : 'numeric' ,
    timeZone : 'UTC' 
  });
  return  (
Calendar 
      {...props }
      aria-label ="Appointment date" 
      visibleDuration ={{months : 2 }}
       style ={{display : 'flex' , gap : 12 , overflow : 'auto' }}
    >
      {({state}) => (
        [...Array(props .visibleDuration .months ).keys ()].map (i  => (
          <div  key ={i } style ={{flex : 1 }}>
            <header  style ={{minHeight : 32 }}>
              {i  === 0  && 
                <Button  slot ="previous"  variant ="quiet" >
                  <ChevronLeft  />
                </Button >
              }
              <Heading >{monthFormatter .format (state .visibleRange .start .add ({months : i }).toDate (state .timeZone ))}</Heading >
              {i  === props .visibleDuration .months  - 1  && 
                <Button  slot ="next"  variant ="quiet" >
                  <ChevronRight  />
                </Button >
              }
            </header >
            <CalendarGrid  offset ={{months : i }}>
              {date  => <CalendarCell  date ={date } />}
            </CalendarGrid >
          </div >
        ))
      )}
    </Calendar >
  );
}
Expand code 
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.
Today 
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} from  './Calendar' ;
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 ()))}>
Button >
      <Calendar 
        focusedValue ={focusedDate }
        onFocusChange ={setFocusedDate }
       />
    </div >
  );
}
Expand code 
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 <Calendar>.
October 2025 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
Example 
MonthDropdown.tsx 
YearDropdown.tsx 
Example 
MonthDropdown.tsx 
YearDropdown.tsx 
MonthDropdown.tsx 
YearDropdown.tsx 
import  {Calendar} from  'react-aria-components' ;
import  {CalendarGrid, CalendarCell} from  './Calendar' ;
import  {MonthDropdown} from  './MonthDropdown' ;
import  {YearDropdown} from  './YearDropdown' ;
import  {Button} from  './Button' ;
import  {ChevronLeft, ChevronRight} from  'lucide-react' ;
<Calendar >
  <header  style ={{display : 'flex' , gap : 4 }}>
Button  slot ="previous"  variant ="quiet" >
      <ChevronLeft  />
    </Button >
    <MonthDropdown  />
    <YearDropdown  />
     <Button  slot ="next"  variant ="quiet" >
      <ChevronRight  />
    </Button >
  </header >
  <CalendarGrid >
    {(date ) => <CalendarCell  date ={date } />}
  </CalendarGrid >
</Calendar >
Expand code 
API 
September 2021 S M T W T F 5 7 8 9 10 13 14 15 16 19 20 21 22 23 24 1 2 3 26 27 29 30 6 28 S 11 18 25 4 Cell Grid Next button 12 17 6 Previous button