Skip to content
+

Calendar

POC of a Calendar component using the Base UI DX.

Anatomy

Days

<Calendar.Root>
  <Calendar.DayGrid>
    <Calendar.DayGridHeader>
      {({ days }) => days.map((day) => <Calendar.DayGridHeaderCell value={day} />)}
    </Calendar.DayGridHeader>
    <Calendar.DayGridBody>
      {({ weeks }) =>
        weeks.map((week) => (
          <Calendar.DayGridRow value={week}>
            {({ days }) => days.map((day) => <Calendar.DayCell value={day} />)}
          </Calendar.DayGridRow>
        ))
      }
    </Calendar.DayGridBody>
  </Calendar.DayGrid>
</Calendar.Root>

Months

// Grid layout
<Calendar.Root>
  <Calendar.MonthGrid>
    {({ months }) => months.map((month) => <Calendar.MonthCell value={month} />)}
  </Calendar.MonthGrid>
</Calendar.Root>

// List layout
<Calendar.Root>
  <Calendar.MonthList>
    {({ months }) => months.map((month) => <Calendar.MonthCell value={month} />)}
  </Calendar.MonthList>
</Calendar.Root>

Years

// Grid layout
<Calendar.Root>
  <Calendar.YearGrid>
    {({ years }) => years.map((year) => <Calendar.YearCell value={year} />)}
  </Calendar.YearGrid>
</Calendar.Root>

// List layout
<Calendar.Root>
  <Calendar.YearList>
    {({ years }) => years.map((year) => <Calendar.YearCell value={year} />)}
  </Calendar.YearList>
</Calendar.Root>
<Calendar.Root>
  <Calendar.SetVisibleYear />
  <Calendar.SetVisibleMonth />
</Calendar.Root>

Day Calendar

Single visible month

May 2025
SMTWTFS

Multiple visible months

  1. Add the offset prop to each of the <Calendar.DayGrid />

    <React.Fragment>
      <Calendar.DayGrid offset={0}>
        {/** Children for the 1st month **/}
      </Calendar.DayGrid>
      <Calendar.DayGrid offset={1}>
        {/** Children for the 2nd month **/}
      </Calendar.DayGrid>
    </React.Fragment>
    
  2. Add the monthPageSize prop to the <Calendar.Root />

    <Calendar.Root monthPageSize={2}>{children}</Calendar.Root>
    

    It will make sure that keyboard navigation and pressing <Calendar.SetVisibleMonth /> switching month two by two.

May 2025
June 2025
SMTWTFS
SMTWTFS

With validation

For now, the validation behaviors are exactly the same as on <DateCalendar />:

<Calendar.Root disablePast>{children}</Calendar.Root>
May 2025
SMTWTFS

With fixed week number

<Calendar.DayGridBody fixedWeekNumber={6}>{children}</Calendar.DayGridBody>
May 2025
SMTWTFS

Recipe: With week number

  1. Add a custom cell in <Calendar.DayGridHeader />

    <Calendar.DayGridHeader>
      {({ days }) => (
        <React.Fragment>
          <span role="columnheader" aria-label="Week number">
            #
          </span>
          {/** Day header cells **/}
        </React.Fragment>
      )}
    </Calendar.DayGridHeader>
    
  2. Add a custom cell in <Calendar.DayGridRow />

    <Calendar.DayGridRow value={week}>
      {({ days }) => (
        <React.Fragment>
          <span role="rowheader" aria-label={`Week ${days[0].week()}`}>
            {days[0].week()}
          </span>
          {/** Day cells */}
        </React.Fragment>
      )}
    </Calendar.DayGridRow>
    
May 2025
#SMTWTFS
18
19
20
21
22
2025
2025

Custom cell format

<Calendar.MonthCell value={month} format="MMM" />
2025
Press Enter to start editing

Recipe: Reversed order

const getYears = ({ getDefaultItems }) => {
  return getDefaultItems().toReversed();
};

<Calendar.YearGrid cellsPerRow={2} getItems={getYearsInDecade}>
  {/** Year cells */}
</Calendar.YearGrid>;

Recipe: Grouped by decade

const getYearsInDecade = ({ visibleDate }) => {
  const reference = visibleDate.startOf('year');
  const decade = Math.floor(reference.year() / 10) * 10;
  return Array.from({ length: 10 }, (_, index) =>
    reference.set('year', decade + index),
  );
};

<Calendar.YearGrid cellsPerRow={2} getItems={getYearsInDecade}>
  {/** Year cells */}
</Calendar.YearGrid>;
2020s
SMTWTFS
SMTWTFS

Recipe: Material Design 2

This is a reproduction of the Date Calendar component, with the following simplification:

  • The order of the views is not overridable
  • Some props are not implemented (reduceAnimations, disableDayMargin, ...)

This shows how light the Material layer would be once we have the Base UI X primitives.

SMTWTFS

Recipe: Year accordion