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>
Navigation
<Calendar.Root>
<Calendar.SetVisibleYear />
<Calendar.SetVisibleMonth />
</Calendar.Root>
Day Calendar
Single visible month
SMTWTFS
Multiple visible months
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>
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>
SMTWTFS
With fixed week number
<Calendar.DayGridBody fixedWeekNumber={6}>{children}</Calendar.DayGridBody>
SMTWTFS
Recipe: With week number
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>
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>
#SMTWTFS
18
19
20
21
22
Custom cell format
<Calendar.MonthCell value={month} format="MMM" />
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>;
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.
May 2025
SMTWTFS