---
title: Calendar
subtitle: An easily stylable calendar component.
description: A high-quality, unstyled React calendar that is easy to customize.
---

# Calendar

A high-quality, unstyled React calendar that is easy to customize.

## Demo

### CSS Modules

This example shows how to implement the component using CSS Modules.

```tsx
/* index.tsx */
'use client';
import * as React from 'react';
import { format } from 'date-fns/format';
import { Calendar } from '@base-ui/react/calendar';
import styles from './calendar.module.css';

export default function ExampleCalendar() {
  return (
    <Calendar.Root className={styles.Root}>
      {({ visibleDate }) => (
        <React.Fragment>
          <header className={styles.Header}>
            <Calendar.DecrementMonth className={styles.DecrementMonth}>
              <ChevronLeftIcon />
            </Calendar.DecrementMonth>
            <span className={styles.HeaderLabel}>{format(visibleDate, 'MMMM yyyy')}</span>
            <Calendar.IncrementMonth className={styles.IncrementMonth}>
              <ChevronRightIcon />
            </Calendar.IncrementMonth>
          </header>
          <Calendar.DayGrid className={styles.DayGrid}>
            <Calendar.DayGridHeader className={styles.DayGridHeader}>
              <Calendar.DayGridHeaderRow className={styles.DayGridHeaderRow}>
                {(day) => (
                  <Calendar.DayGridHeaderCell
                    value={day}
                    key={day.getTime()}
                    className={styles.DayGridHeaderCell}
                  />
                )}
              </Calendar.DayGridHeaderRow>
            </Calendar.DayGridHeader>
            <Calendar.DayGridBody className={styles.DayGridBody}>
              {(week) => (
                <Calendar.DayGridRow
                  value={week}
                  key={week.getTime()}
                  className={styles.DayGridRow}
                >
                  {(day) => (
                    <Calendar.DayGridCell
                      value={day}
                      key={day.getTime()}
                      className={styles.DayGridCell}
                    >
                      <Calendar.DayButton className={styles.DayButton} />
                    </Calendar.DayGridCell>
                  )}
                </Calendar.DayGridRow>
              )}
            </Calendar.DayGridBody>
          </Calendar.DayGrid>
        </React.Fragment>
      )}
    </Calendar.Root>
  );
}

function ChevronLeftIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m15 18-6-6 6-6" />
    </svg>
  );
}

function ChevronRightIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m9 18 6-6-6-6" />
    </svg>
  );
}
```

```css
/* calendar.module.css */
.Root {
  border: 1px solid var(--calendar-root-border-color);
  border-radius: 8px;
  height: 312px;
  display: flex;
  flex-direction: column;

  --calendar-root-color: var(--color-gray-900);
  --calendar-root-border-color: var(--color-gray-500);
  --calendar-button-hover-bg-color: var(--color-gray-100);
  --calendar-button-focus-border-color: var(--color-blue);
  --calendar-day-grid-separator-bg-color: var(--color-gray-400);
  --calendar-day-grid-header-color: var(--color-gray-500);

  --calendar-cell-selected-bg-color: var(--color-gray-900);
  --calendar-cell-selected-color: var(--color-gray-50);
  --calendar-cell-outside-month-color: var(--color-gray-400);
  --calendar-cell-disabled-color: var(--color-gray-500);
  --calendar-cell-current-border-color: var(--color-gray-500);
  --calendar-cell-unavailable-color: var(--color-red);
}

.Header {
  box-sizing: border-box;
  padding: 8px 12px;
  height: 40px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.HeaderLabel {
  color: var(--calendar-root-color);
}

.DecrementMonth,
.IncrementMonth {
  border: none;
  -webkit-user-select: none;
  user-select: none;
  background-color: transparent;
  border-radius: 4px;
  color: var(--calendar-root-color);
  margin: 0 6px;
  padding: 0;
  display: flex;

  @media (hover: hover) {
    &:hover {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &:focus-visible {
    outline: 2px solid var(--calendar-button-focus-border-color);
  }

  &[data-disabled] {
    pointer-events: none;
    color: var(--calendar-cell-disabled-color);
  }
}

.DayGrid {
  padding: 12px;
  height: 276px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 1;
  position: relative;
}

.DayGridBody {
  display: flex;
  flex-direction: column;
  row-gap: 2px;
}

.DayGridRow,
.DayGridHeaderRow {
  display: flex;
  justify-content: center;
}

.DayGridHeaderCell {
  width: 36px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--calendar-day-grid-header-color);
  font-weight: 700;
  padding: 0;
}

.DayGridCell {
  padding: 0;
}

.DayButton {
  background: none;
  padding: 0;
  font: inherit;
  height: 36px;
  width: 36px;
  position: relative;
  user-select: none;
  border: none;
  background-color: transparent;
  outline: none;
  box-sizing: border-box;
  border-radius: 4px;
  color: var(--calendar-root-color);

  &::before {
    content: '';
    position: absolute;
    inset: 2px;
    border-radius: 4px;
    border: none;
    z-index: -1;
    background-color: transparent;
  }

  &::after {
    content: '';
    border-radius: 4px;
    position: absolute;
    inset: 2px;
  }

  &:not([data-outside-month]):focus-visible {
    &::after {
      outline: 2px solid var(--calendar-button-focus-border-color);
    }
  }

  @media (hover: hover) {
    &:not([data-selected]):hover::before {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &[data-selected]:not([data-outside-month]) {
    color: var(--calendar-cell-selected-color);
  }

  &[data-selected]:not([data-outside-month])::before {
    background-color: var(--calendar-cell-selected-bg-color);
  }

  &[data-disabled] {
    pointer-events: none;
  }

  &:not([data-outside-month])[data-disabled] {
    color: var(--calendar-cell-disabled-color);
  }

  &:not([data-outside-month])[data-invalid] {
    text-decoration: line-through;
  }

  &[data-outside-month] {
    color: var(--calendar-cell-outside-month-color);
    pointer-events: none;
  }

  &[data-current]:not([data-selected], :focus-visible)::after {
    outline: 1px solid var(--calendar-cell-current-border-color);
  }

  &:not([data-disabled], [data-outside-month])[data-unavailable] {
    text-decoration: line-through;
    color: var(--calendar-cell-unavailable-color);
  }
}
```

## Anatomy

Import the component and assemble its parts:

```jsx title="Anatomy"
import { Calendar } from '@base-ui/react/calendar';

<Calendar.Root>
  <Calendar.DecrementMonth />
  <Calendar.IncrementMonth />
  <Calendar.DayGrid>
    <Calendar.DayGridHeader>
      <Calendar.DayGridHeaderRow>
        <Calendar.DayGridHeaderCell />
      </Calendar.DayGridHeaderRow>
    </Calendar.DayGridHeader>
    <Calendar.DayGridBody>
      <Calendar.DayGridRow>
        <Calendar.DayGridCell>
          <Calendar.DayButton />
        </Calendar.DayGridCell>
      </Calendar.DayGridRow>
    </Calendar.DayGridBody>
  </Calendar.DayGrid>
</Calendar.Root>;
```

## Examples

### Unavailable dates

You can use the `isDateUnavailable()` prop to mark specific dates as unavailable. Unavailable dates are visually indicated and cannot be selected, but are focusable.

This example disables weekends, US holidays, and the first Monday of every month.

## Demo

### CSS Modules

This example shows how to implement the component using CSS Modules.

```tsx
/* index.tsx */
'use client';
import * as React from 'react';
import { format } from 'date-fns/format';
import { Calendar } from '@base-ui/react/calendar';
import styles from './calendar.module.css';

const holidays: Array<[number, number]> = [
  [0, 1], // New Year's Day
  [6, 4], // Independence Day
  [10, 11], // Veterans Day
  [11, 25], // Christmas Day
];

function isDateUnavailable(date: Date) {
  const day = date.getDay();
  const month = date.getMonth();
  const dayOfMonth = date.getDate();

  // Weekends
  if (day === 0 || day === 6) {
    return true;
  }

  // US holidays
  if (holidays.some(([m, d]) => month === m && dayOfMonth === d)) {
    return true;
  }

  // First Monday of every month (maintenance day)
  if (day === 1 && dayOfMonth <= 7) {
    return true;
  }

  return false;
}

export default function UnavailableDatesCalendar() {
  return (
    <Calendar.Root
      className={styles.Root}
      isDateUnavailable={isDateUnavailable}
      aria-label="Appointment date"
    >
      {({ visibleDate }) => (
        <React.Fragment>
          <header className={styles.Header}>
            <Calendar.DecrementMonth className={styles.DecrementMonth}>
              <ChevronLeftIcon />
            </Calendar.DecrementMonth>
            <span className={styles.HeaderLabel}>{format(visibleDate, 'MMMM yyyy')}</span>
            <Calendar.IncrementMonth className={styles.IncrementMonth}>
              <ChevronRightIcon />
            </Calendar.IncrementMonth>
          </header>
          <Calendar.DayGrid className={styles.DayGrid}>
            <Calendar.DayGridHeader className={styles.DayGridHeader}>
              <Calendar.DayGridHeaderRow className={styles.DayGridHeaderRow}>
                {(day) => (
                  <Calendar.DayGridHeaderCell
                    value={day}
                    key={day.getTime()}
                    className={styles.DayGridHeaderCell}
                  />
                )}
              </Calendar.DayGridHeaderRow>
            </Calendar.DayGridHeader>
            <Calendar.DayGridBody className={styles.DayGridBody}>
              {(week) => (
                <Calendar.DayGridRow
                  value={week}
                  key={week.getTime()}
                  className={styles.DayGridRow}
                >
                  {(day) => (
                    <Calendar.DayGridCell
                      value={day}
                      key={day.getTime()}
                      className={styles.DayGridCell}
                    >
                      <Calendar.DayButton className={styles.DayButton} />
                    </Calendar.DayGridCell>
                  )}
                </Calendar.DayGridRow>
              )}
            </Calendar.DayGridBody>
          </Calendar.DayGrid>
        </React.Fragment>
      )}
    </Calendar.Root>
  );
}

function ChevronLeftIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m15 18-6-6 6-6" />
    </svg>
  );
}

function ChevronRightIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m9 18 6-6-6-6" />
    </svg>
  );
}
```

```css
/* calendar.module.css */
.Root {
  border: 1px solid var(--calendar-root-border-color);
  border-radius: 8px;
  height: 312px;
  display: flex;
  flex-direction: column;

  --calendar-root-color: var(--color-gray-900);
  --calendar-root-border-color: var(--color-gray-500);
  --calendar-button-hover-bg-color: var(--color-gray-100);
  --calendar-button-focus-border-color: var(--color-blue);
  --calendar-day-grid-separator-bg-color: var(--color-gray-400);
  --calendar-day-grid-header-color: var(--color-gray-500);

  --calendar-cell-selected-bg-color: var(--color-gray-900);
  --calendar-cell-selected-color: var(--color-gray-50);
  --calendar-cell-outside-month-color: var(--color-gray-400);
  --calendar-cell-disabled-color: var(--color-gray-500);
  --calendar-cell-current-border-color: var(--color-gray-500);
  --calendar-cell-unavailable-color: var(--color-red);
}

.Header {
  box-sizing: border-box;
  padding: 8px 12px;
  height: 40px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.HeaderLabel {
  color: var(--calendar-root-color);
}

.DecrementMonth,
.IncrementMonth {
  border: none;
  -webkit-user-select: none;
  user-select: none;
  background-color: transparent;
  border-radius: 4px;
  color: var(--calendar-root-color);
  margin: 0 6px;
  padding: 0;
  display: flex;

  @media (hover: hover) {
    &:hover {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &:focus-visible {
    outline: 2px solid var(--calendar-button-focus-border-color);
  }

  &[data-disabled] {
    pointer-events: none;
    color: var(--calendar-cell-disabled-color);
  }
}

.DayGrid {
  padding: 12px;
  height: 276px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 1;
  position: relative;
}

.DayGridBody {
  display: flex;
  flex-direction: column;
  row-gap: 2px;
}

.DayGridRow,
.DayGridHeaderRow {
  display: flex;
  justify-content: center;
}

.DayGridHeaderCell {
  width: 36px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--calendar-day-grid-header-color);
  font-weight: 700;
  padding: 0;
}

.DayGridCell {
  padding: 0;
}

.DayButton {
  background: none;
  padding: 0;
  font: inherit;
  height: 36px;
  width: 36px;
  position: relative;
  user-select: none;
  border: none;
  background-color: transparent;
  outline: none;
  box-sizing: border-box;
  border-radius: 4px;
  color: var(--calendar-root-color);

  &::before {
    content: '';
    position: absolute;
    inset: 2px;
    border-radius: 4px;
    border: none;
    z-index: -1;
    background-color: transparent;
  }

  &::after {
    content: '';
    border-radius: 4px;
    position: absolute;
    inset: 2px;
  }

  &:not([data-outside-month]):focus-visible {
    &::after {
      outline: 2px solid var(--calendar-button-focus-border-color);
    }
  }

  @media (hover: hover) {
    &:not([data-selected]):hover::before {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &[data-selected]:not([data-outside-month]) {
    color: var(--calendar-cell-selected-color);
  }

  &[data-selected]:not([data-outside-month])::before {
    background-color: var(--calendar-cell-selected-bg-color);
  }

  &[data-disabled] {
    pointer-events: none;
  }

  &:not([data-outside-month])[data-disabled] {
    color: var(--calendar-cell-disabled-color);
  }

  &:not([data-outside-month])[data-invalid] {
    text-decoration: line-through;
  }

  &[data-outside-month] {
    color: var(--calendar-cell-outside-month-color);
    pointer-events: none;
  }

  &[data-current]:not([data-selected], :focus-visible)::after {
    outline: 1px solid var(--calendar-cell-current-border-color);
  }

  &:not([data-disabled], [data-outside-month])[data-unavailable] {
    text-decoration: line-through;
    color: var(--calendar-cell-unavailable-color);
  }
}
```

### Validation

You can use the `minDate` and `maxDate` props to limit the range of selectable dates.

## Demo

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.Wrapper {
  display: flex;
  flex-flow: row wrap;
  gap: 24px;
  justify-content: center;
}
```

```tsx
/* index.tsx */
'use client';
import * as React from 'react';
import { format } from 'date-fns/format';
import { Calendar } from '@base-ui/react/calendar';
import indexStyles from './index.module.css';
import styles from './calendar.module.css';

const today = new Date();

export default function MinMaxDateCalendars() {
  return (
    <div className={indexStyles.Wrapper}>
      <ValidationCalendar minDate={today} />
      <ValidationCalendar maxDate={today} />
    </div>
  );
}

function ValidationCalendar(props: Calendar.Root.Props) {
  return (
    <Calendar.Root className={styles.Root} {...props}>
      {({ visibleDate }) => (
        <React.Fragment>
          <header className={styles.Header}>
            <Calendar.DecrementMonth className={styles.DecrementMonth}>
              <ChevronLeftIcon />
            </Calendar.DecrementMonth>
            <span className={styles.HeaderLabel}>{format(visibleDate, 'MMMM yyyy')}</span>
            <Calendar.IncrementMonth className={styles.IncrementMonth}>
              <ChevronRightIcon />
            </Calendar.IncrementMonth>
          </header>
          <Calendar.DayGrid className={styles.DayGrid}>
            <Calendar.DayGridHeader className={styles.DayGridHeader}>
              <Calendar.DayGridHeaderRow className={styles.DayGridHeaderRow}>
                {(day) => (
                  <Calendar.DayGridHeaderCell
                    value={day}
                    key={day.getTime()}
                    className={styles.DayGridHeaderCell}
                  />
                )}
              </Calendar.DayGridHeaderRow>
            </Calendar.DayGridHeader>
            <Calendar.DayGridBody className={styles.DayGridBody}>
              {(week) => (
                <Calendar.DayGridRow
                  value={week}
                  key={week.getTime()}
                  className={styles.DayGridRow}
                >
                  {(day) => (
                    <Calendar.DayGridCell
                      value={day}
                      key={day.getTime()}
                      className={styles.DayGridCell}
                    >
                      <Calendar.DayButton className={styles.DayButton} />
                    </Calendar.DayGridCell>
                  )}
                </Calendar.DayGridRow>
              )}
            </Calendar.DayGridBody>
          </Calendar.DayGrid>
        </React.Fragment>
      )}
    </Calendar.Root>
  );
}

function ChevronLeftIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m15 18-6-6 6-6" />
    </svg>
  );
}

function ChevronRightIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m9 18 6-6-6-6" />
    </svg>
  );
}
```

```css
/* calendar.module.css */
.Root {
  border: 1px solid var(--calendar-root-border-color);
  border-radius: 8px;
  height: 312px;
  display: flex;
  flex-direction: column;

  --calendar-root-color: var(--color-gray-900);
  --calendar-root-border-color: var(--color-gray-500);
  --calendar-button-hover-bg-color: var(--color-gray-100);
  --calendar-button-focus-border-color: var(--color-blue);
  --calendar-day-grid-separator-bg-color: var(--color-gray-400);
  --calendar-day-grid-header-color: var(--color-gray-500);

  --calendar-cell-selected-bg-color: var(--color-gray-900);
  --calendar-cell-selected-color: var(--color-gray-50);
  --calendar-cell-outside-month-color: var(--color-gray-400);
  --calendar-cell-disabled-color: var(--color-gray-500);
  --calendar-cell-current-border-color: var(--color-gray-500);
  --calendar-cell-unavailable-color: var(--color-red);
}

.Header {
  box-sizing: border-box;
  padding: 8px 12px;
  height: 40px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.HeaderLabel {
  color: var(--calendar-root-color);
}

.DecrementMonth,
.IncrementMonth {
  border: none;
  -webkit-user-select: none;
  user-select: none;
  background-color: transparent;
  border-radius: 4px;
  color: var(--calendar-root-color);
  margin: 0 6px;
  padding: 0;
  display: flex;

  @media (hover: hover) {
    &:hover {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &:focus-visible {
    outline: 2px solid var(--calendar-button-focus-border-color);
  }

  &[data-disabled] {
    pointer-events: none;
    color: var(--calendar-cell-disabled-color);
  }
}

.DayGrid {
  padding: 12px;
  height: 276px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 1;
  position: relative;
}

.DayGridBody {
  display: flex;
  flex-direction: column;
  row-gap: 2px;
}

.DayGridRow,
.DayGridHeaderRow {
  display: flex;
  justify-content: center;
}

.DayGridHeaderCell {
  width: 36px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--calendar-day-grid-header-color);
  font-weight: 700;
  padding: 0;
}

.DayGridCell {
  padding: 0;
}

.DayButton {
  background: none;
  padding: 0;
  font: inherit;
  height: 36px;
  width: 36px;
  position: relative;
  user-select: none;
  border: none;
  background-color: transparent;
  outline: none;
  box-sizing: border-box;
  border-radius: 4px;
  color: var(--calendar-root-color);

  &::before {
    content: '';
    position: absolute;
    inset: 2px;
    border-radius: 4px;
    border: none;
    z-index: -1;
    background-color: transparent;
  }

  &::after {
    content: '';
    border-radius: 4px;
    position: absolute;
    inset: 2px;
  }

  &:not([data-outside-month]):focus-visible {
    &::after {
      outline: 2px solid var(--calendar-button-focus-border-color);
    }
  }

  @media (hover: hover) {
    &:not([data-selected]):hover::before {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &[data-selected]:not([data-outside-month]) {
    color: var(--calendar-cell-selected-color);
  }

  &[data-selected]:not([data-outside-month])::before {
    background-color: var(--calendar-cell-selected-bg-color);
  }

  &[data-disabled] {
    pointer-events: none;
  }

  &:not([data-outside-month])[data-disabled] {
    color: var(--calendar-cell-disabled-color);
  }

  &:not([data-outside-month])[data-invalid] {
    text-decoration: line-through;
  }

  &[data-outside-month] {
    color: var(--calendar-cell-outside-month-color);
    pointer-events: none;
  }

  &[data-current]:not([data-selected], :focus-visible)::after {
    outline: 1px solid var(--calendar-cell-current-border-color);
  }

  &:not([data-disabled], [data-outside-month])[data-unavailable] {
    text-decoration: line-through;
    color: var(--calendar-cell-unavailable-color);
  }
}
```

### Lazy loading

You can render custom content inside `<Calendar.DayButton>` and use `Calendar.useContext()` to
react to month changes — for example, to lazily load per-day data.

## Demo

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.Root {
  height: 420px;
}

.DayGrid {
  height: 384px;
}

.DayGridHeaderCell {
  width: 44px;
}

.DayButton {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 52px;
  width: 44px;
  gap: 2px;
}

.DayNumber {
  font-size: 0.9375rem;
  font-weight: 400;
  line-height: 1;
}

.Price {
  font-size: 0.625rem;
  line-height: 1;
  color: var(--color-gray-500);

  @media (prefers-reduced-motion: no-preference) {
    animation: fadeIn 0.2s ease both;
  }
}

.PriceDeal {
  color: oklch(52% 40% 150deg);
  font-weight: 700;

  @media (prefers-color-scheme: dark) {
    color: oklch(72% 35% 150deg);
  }
}

.PriceSoldOut {
  font-size: 0.625rem;
  line-height: 1;
  color: var(--color-gray-400);

  @media (prefers-reduced-motion: no-preference) {
    animation: fadeIn 0.2s ease both;
  }
}

.DayButton[data-selected]:not([data-outside-month]) .Price,
.DayButton[data-selected]:not([data-outside-month]) .PriceSoldOut {
  color: inherit;
}

.Skeleton {
  display: block;
  width: 24px;
  height: 10px;
  border-radius: 2px;
  background: linear-gradient(
    90deg,
    var(--color-gray-300) 25%,
    var(--color-gray-200) 50%,
    var(--color-gray-300) 75%
  );
  background-size: 200% 100%;

  @media (prefers-reduced-motion: no-preference) {
    animation: shimmer 1.5s ease-in-out infinite;
  }
}

@keyframes shimmer {
  0% {
    background-position: 200% 0;
  }

  100% {
    background-position: -200% 0;
  }
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}
```

```tsx
/* index.tsx */
'use client';
import * as React from 'react';
import clsx from 'clsx';
import { format } from 'date-fns/format';
import { Calendar } from '@base-ui/react/calendar';
import { useTimeout } from '@base-ui/utils/useTimeout';
import styles from './calendar.module.css';
import indexStyles from './index.module.css';

function DayPrice({
  loading,
  price,
  isDeal,
  loadingDelay,
  revealDelay,
}: {
  loading: boolean;
  price: number | null | undefined;
  isDeal: boolean;
  loadingDelay: string;
  revealDelay: string;
}) {
  if (loading) {
    return (
      <span
        className={indexStyles.Skeleton}
        style={{ animationDelay: loadingDelay }}
        aria-hidden="true"
      />
    );
  }
  if (price != null) {
    return (
      <span
        className={clsx(indexStyles.Price, isDeal && indexStyles.PriceDeal)}
        style={{ animationDelay: revealDelay }}
      >
        ${price}
      </span>
    );
  }
  return (
    <span className={indexStyles.PriceSoldOut} style={{ animationDelay: revealDelay }}>
      —
    </span>
  );
}

function CalendarContent() {
  const { visibleDate } = Calendar.useContext();
  const [prices, setPrices] = React.useState<Record<string, number | null>>({});
  const [loading, setLoading] = React.useState(true);
  const timeout = useTimeout();

  const monthKey = format(visibleDate, 'yyyy-MM');

  React.useEffect(() => {
    const year = parseInt(monthKey.split('-')[0], 10);
    const month = parseInt(monthKey.split('-')[1], 10) - 1;
    setLoading(true);
    timeout.start(800, () => {
      setPrices((prev) => ({ ...prev, ...generateMonthPrices(year, month) }));
      setLoading(false);
    });
  }, [monthKey, timeout]);

  const minPrice = React.useMemo(() => {
    const monthPrices = Object.entries(prices)
      .filter(([key]) => key.startsWith(monthKey))
      .flatMap(([, p]) => (p != null ? [p] : []));
    return monthPrices.length > 0 ? Math.min(...monthPrices) : null;
  }, [prices, monthKey]);

  return (
    <React.Fragment>
      <header className={styles.Header}>
        <Calendar.DecrementMonth className={styles.DecrementMonth}>
          <ChevronLeftIcon />
        </Calendar.DecrementMonth>
        <span className={styles.HeaderLabel}>{format(visibleDate, 'MMMM yyyy')}</span>
        <Calendar.IncrementMonth className={styles.IncrementMonth}>
          <ChevronRightIcon />
        </Calendar.IncrementMonth>
      </header>
      <Calendar.DayGrid className={clsx(styles.DayGrid, indexStyles.DayGrid)}>
        <Calendar.DayGridHeader className={styles.DayGridHeader}>
          <Calendar.DayGridHeaderRow className={styles.DayGridHeaderRow}>
            {(day) => (
              <Calendar.DayGridHeaderCell
                value={day}
                key={day.getTime()}
                className={clsx(styles.DayGridHeaderCell, indexStyles.DayGridHeaderCell)}
              />
            )}
          </Calendar.DayGridHeaderRow>
        </Calendar.DayGridHeader>
        <Calendar.DayGridBody className={styles.DayGridBody}>
          {(week) => (
            <Calendar.DayGridRow value={week} key={week.getTime()} className={styles.DayGridRow}>
              {(day) => {
                const dateKey = format(day, 'yyyy-MM-dd');
                const inCurrentMonth = dateKey.startsWith(monthKey);
                const price = prices[dateKey];
                const isDeal = inCurrentMonth && price != null && price === minPrice;
                const daySeed =
                  day.getFullYear() * 10000 + (day.getMonth() + 1) * 100 + day.getDate();
                const loadingDelay = `${(seededRandom(daySeed + 50) * 0.4).toFixed(3)}s`;
                const revealDelay = `${(seededRandom(daySeed + 60) * 0.5).toFixed(3)}s`;
                return (
                  <Calendar.DayGridCell
                    value={day}
                    key={day.getTime()}
                    className={styles.DayGridCell}
                  >
                    <Calendar.DayButton className={clsx(styles.DayButton, indexStyles.DayButton)}>
                      <span className={indexStyles.DayNumber}>{format(day, 'd')}</span>
                      {inCurrentMonth && (
                        <DayPrice
                          loading={loading}
                          price={price}
                          isDeal={isDeal}
                          loadingDelay={loadingDelay}
                          revealDelay={revealDelay}
                        />
                      )}
                    </Calendar.DayButton>
                  </Calendar.DayGridCell>
                );
              }}
            </Calendar.DayGridRow>
          )}
        </Calendar.DayGridBody>
      </Calendar.DayGrid>
    </React.Fragment>
  );
}

export default function FlightPriceCalendar() {
  return (
    <Calendar.Root
      className={clsx(styles.Root, indexStyles.Root)}
      aria-label="Flight departure date"
    >
      <CalendarContent />
    </Calendar.Root>
  );
}

function seededRandom(seed: number) {
  const x = Math.sin(seed) * 10000;
  return x - Math.floor(x);
}

function generateMonthPrices(year: number, month: number): Record<string, number | null> {
  const prices: Record<string, number | null> = {};
  const daysInMonth = new Date(year, month + 1, 0).getDate();
  for (let d = 1; d <= daysInMonth; d += 1) {
    const date = new Date(year, month, d);
    const dateKey = format(date, 'yyyy-MM-dd');
    const seed = year * 10000 + (month + 1) * 100 + d;
    const rand = seededRandom(seed);
    prices[dateKey] = rand < 0.15 ? null : Math.floor(79 + seededRandom(seed + 1) * 320);
  }
  return prices;
}

function ChevronLeftIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m15 18-6-6 6-6" />
    </svg>
  );
}

function ChevronRightIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m9 18 6-6-6-6" />
    </svg>
  );
}
```

```css
/* calendar.module.css */
.Root {
  border: 1px solid var(--calendar-root-border-color);
  border-radius: 8px;
  height: 312px;
  display: flex;
  flex-direction: column;

  --calendar-root-color: var(--color-gray-900);
  --calendar-root-border-color: var(--color-gray-500);
  --calendar-button-hover-bg-color: var(--color-gray-100);
  --calendar-button-focus-border-color: var(--color-blue);
  --calendar-day-grid-separator-bg-color: var(--color-gray-400);
  --calendar-day-grid-header-color: var(--color-gray-500);

  --calendar-cell-selected-bg-color: var(--color-gray-900);
  --calendar-cell-selected-color: var(--color-gray-50);
  --calendar-cell-outside-month-color: var(--color-gray-400);
  --calendar-cell-disabled-color: var(--color-gray-500);
  --calendar-cell-current-border-color: var(--color-gray-500);
  --calendar-cell-unavailable-color: var(--color-red);
}

.Header {
  box-sizing: border-box;
  padding: 8px 12px;
  height: 40px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.HeaderLabel {
  color: var(--calendar-root-color);
}

.DecrementMonth,
.IncrementMonth {
  border: none;
  -webkit-user-select: none;
  user-select: none;
  background-color: transparent;
  border-radius: 4px;
  color: var(--calendar-root-color);
  margin: 0 6px;
  padding: 0;
  display: flex;

  @media (hover: hover) {
    &:hover {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &:focus-visible {
    outline: 2px solid var(--calendar-button-focus-border-color);
  }

  &[data-disabled] {
    pointer-events: none;
    color: var(--calendar-cell-disabled-color);
  }
}

.DayGrid {
  padding: 12px;
  height: 276px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 1;
  position: relative;
}

.DayGridBody {
  display: flex;
  flex-direction: column;
  row-gap: 2px;
}

.DayGridRow,
.DayGridHeaderRow {
  display: flex;
  justify-content: center;
}

.DayGridHeaderCell {
  width: 36px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--calendar-day-grid-header-color);
  font-weight: 700;
  padding: 0;
}

.DayGridCell {
  padding: 0;
}

.DayButton {
  background: none;
  padding: 0;
  font: inherit;
  height: 36px;
  width: 36px;
  position: relative;
  user-select: none;
  border: none;
  background-color: transparent;
  outline: none;
  box-sizing: border-box;
  border-radius: 4px;
  color: var(--calendar-root-color);

  &::before {
    content: '';
    position: absolute;
    inset: 2px;
    border-radius: 4px;
    border: none;
    z-index: -1;
    background-color: transparent;
  }

  &::after {
    content: '';
    border-radius: 4px;
    position: absolute;
    inset: 2px;
  }

  &:not([data-outside-month]):focus-visible {
    &::after {
      outline: 2px solid var(--calendar-button-focus-border-color);
    }
  }

  @media (hover: hover) {
    &:not([data-selected]):hover::before {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &[data-selected]:not([data-outside-month]) {
    color: var(--calendar-cell-selected-color);
  }

  &[data-selected]:not([data-outside-month])::before {
    background-color: var(--calendar-cell-selected-bg-color);
  }

  &[data-disabled] {
    pointer-events: none;
  }

  &:not([data-outside-month])[data-disabled] {
    color: var(--calendar-cell-disabled-color);
  }

  &:not([data-outside-month])[data-invalid] {
    text-decoration: line-through;
  }

  &[data-outside-month] {
    color: var(--calendar-cell-outside-month-color);
    pointer-events: none;
  }

  &[data-current]:not([data-selected], :focus-visible)::after {
    outline: 1px solid var(--calendar-cell-current-border-color);
  }

  &:not([data-disabled], [data-outside-month])[data-unavailable] {
    text-decoration: line-through;
    color: var(--calendar-cell-unavailable-color);
  }
}
```

### Display week numbers

You can use `useWeekList()` and `useDayList()` hooks to build a calendar with additional DOM elements, like week numbers.

## Demo

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.DayWeekNumber {
  height: 36px;
  width: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  color: var(--calendar-day-grid-header-color);
  /* Avoid the bold font weight from the th element */
  font-weight: 700;
  padding: 0;
}
```

```tsx
/* index.tsx */
'use client';
import * as React from 'react';
import { format } from 'date-fns/format';
import { startOfWeek } from 'date-fns/startOfWeek';
import { startOfMonth } from 'date-fns/startOfMonth';
import { getWeek } from 'date-fns/getWeek';
import { Calendar } from '@base-ui/react/calendar';
import styles from './calendar.module.css';
import indexStyles from './index.module.css';

export default function CalendarWithWeekNumbers() {
  const getWeekList = Calendar.useWeekList();
  const getDayList = Calendar.useDayList();

  return (
    <Calendar.Root className={styles.Root}>
      {({ visibleDate }) => (
        <React.Fragment>
          <header className={styles.Header}>
            <Calendar.DecrementMonth className={styles.DecrementMonth}>
              <ChevronLeftIcon />
            </Calendar.DecrementMonth>
            <span className={styles.HeaderLabel}>{format(visibleDate, 'MMMM yyyy')}</span>
            <Calendar.IncrementMonth className={styles.IncrementMonth}>
              <ChevronRightIcon />
            </Calendar.IncrementMonth>
          </header>
          <Calendar.DayGrid className={styles.DayGrid}>
            <Calendar.DayGridHeader className={styles.DayGridHeader}>
              <Calendar.DayGridHeaderRow className={styles.DayGridHeaderRow}>
                <th
                  role="columnheader"
                  aria-label="Week number"
                  className={styles.DayGridHeaderCell}
                >
                  #
                </th>
                {getDayList({ date: startOfWeek(new Date()), amount: 7 }).map((day) => (
                  <Calendar.DayGridHeaderCell
                    value={day}
                    key={day.getTime()}
                    className={styles.DayGridHeaderCell}
                  />
                ))}
              </Calendar.DayGridHeaderRow>
            </Calendar.DayGridHeader>
            <Calendar.DayGridBody className={styles.DayGridBody}>
              {getWeekList({
                date: startOfMonth(visibleDate),
                amount: 'end-of-month',
              }).map((week) => (
                <Calendar.DayGridRow
                  value={week}
                  key={week.getTime()}
                  className={styles.DayGridRow}
                >
                  <th
                    className={indexStyles.DayWeekNumber}
                    scope="row"
                    aria-label={`Week ${getWeek(week)}`}
                  >
                    {getWeek(week)}
                  </th>
                  {getDayList({ date: week, amount: 7 }).map((day) => (
                    <Calendar.DayGridCell
                      value={day}
                      key={day.getTime()}
                      className={styles.DayGridCell}
                    >
                      <Calendar.DayButton className={styles.DayButton} />
                    </Calendar.DayGridCell>
                  ))}
                </Calendar.DayGridRow>
              ))}
            </Calendar.DayGridBody>
          </Calendar.DayGrid>
        </React.Fragment>
      )}
    </Calendar.Root>
  );
}

function ChevronLeftIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m15 18-6-6 6-6" />
    </svg>
  );
}

function ChevronRightIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m9 18 6-6-6-6" />
    </svg>
  );
}
```

```css
/* calendar.module.css */
.Root {
  border: 1px solid var(--calendar-root-border-color);
  border-radius: 8px;
  height: 312px;
  display: flex;
  flex-direction: column;

  --calendar-root-color: var(--color-gray-900);
  --calendar-root-border-color: var(--color-gray-500);
  --calendar-button-hover-bg-color: var(--color-gray-100);
  --calendar-button-focus-border-color: var(--color-blue);
  --calendar-day-grid-separator-bg-color: var(--color-gray-400);
  --calendar-day-grid-header-color: var(--color-gray-500);

  --calendar-cell-selected-bg-color: var(--color-gray-900);
  --calendar-cell-selected-color: var(--color-gray-50);
  --calendar-cell-outside-month-color: var(--color-gray-400);
  --calendar-cell-disabled-color: var(--color-gray-500);
  --calendar-cell-current-border-color: var(--color-gray-500);
  --calendar-cell-unavailable-color: var(--color-red);
}

.Header {
  box-sizing: border-box;
  padding: 8px 12px;
  height: 40px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.HeaderLabel {
  color: var(--calendar-root-color);
}

.DecrementMonth,
.IncrementMonth {
  border: none;
  -webkit-user-select: none;
  user-select: none;
  background-color: transparent;
  border-radius: 4px;
  color: var(--calendar-root-color);
  margin: 0 6px;
  padding: 0;
  display: flex;

  @media (hover: hover) {
    &:hover {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &:focus-visible {
    outline: 2px solid var(--calendar-button-focus-border-color);
  }

  &[data-disabled] {
    pointer-events: none;
    color: var(--calendar-cell-disabled-color);
  }
}

.DayGrid {
  padding: 12px;
  height: 276px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 1;
  position: relative;
}

.DayGridBody {
  display: flex;
  flex-direction: column;
  row-gap: 2px;
}

.DayGridRow,
.DayGridHeaderRow {
  display: flex;
  justify-content: center;
}

.DayGridHeaderCell {
  width: 36px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--calendar-day-grid-header-color);
  font-weight: 700;
  padding: 0;
}

.DayGridCell {
  padding: 0;
}

.DayButton {
  background: none;
  padding: 0;
  font: inherit;
  height: 36px;
  width: 36px;
  position: relative;
  user-select: none;
  border: none;
  background-color: transparent;
  outline: none;
  box-sizing: border-box;
  border-radius: 4px;
  color: var(--calendar-root-color);

  &::before {
    content: '';
    position: absolute;
    inset: 2px;
    border-radius: 4px;
    border: none;
    z-index: -1;
    background-color: transparent;
  }

  &::after {
    content: '';
    border-radius: 4px;
    position: absolute;
    inset: 2px;
  }

  &:not([data-outside-month]):focus-visible {
    &::after {
      outline: 2px solid var(--calendar-button-focus-border-color);
    }
  }

  @media (hover: hover) {
    &:not([data-selected]):hover::before {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &[data-selected]:not([data-outside-month]) {
    color: var(--calendar-cell-selected-color);
  }

  &[data-selected]:not([data-outside-month])::before {
    background-color: var(--calendar-cell-selected-bg-color);
  }

  &[data-disabled] {
    pointer-events: none;
  }

  &:not([data-outside-month])[data-disabled] {
    color: var(--calendar-cell-disabled-color);
  }

  &:not([data-outside-month])[data-invalid] {
    text-decoration: line-through;
  }

  &[data-outside-month] {
    color: var(--calendar-cell-outside-month-color);
    pointer-events: none;
  }

  &[data-current]:not([data-selected], :focus-visible)::after {
    outline: 1px solid var(--calendar-cell-current-border-color);
  }

  &:not([data-disabled], [data-outside-month])[data-unavailable] {
    text-decoration: line-through;
    color: var(--calendar-cell-unavailable-color);
  }
}
```

### Timezone support

You can use the `timezone` prop to display data in the calendar in your preferred timezone.

Timezone support is based on [@date-fns/tz](https://github.com/date-fns/tz).

## Demo

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.Wrapper {
  display: flex;
  flex-flow: row wrap;
  justify-content: center;
}

.Text {
  color: var(--color-gray-900);
  width: 100%;
  text-align: center;
}
```

```tsx
/* index.tsx */
'use client';
import * as React from 'react';
import { format } from 'date-fns/format';
import { TZDate } from '@date-fns/tz';
import { Calendar } from '@base-ui/react/calendar';
import styles from './calendar.module.css';
import indexStyles from './index.module.css';

export default function CalendarWithTimezone() {
  const [value, setValue] = React.useState<Date | null>(
    new TZDate(2025, 3, 17, 4, 45, 0, 0, 'Europe/Paris'),
  );
  return (
    <div className={indexStyles.Wrapper}>
      <p className={indexStyles.Text}>
        Calendar is displayed in <strong>America/New_York</strong> timezone.
      </p>
      <Calendar.Root
        className={styles.Root}
        timezone="America/New_York"
        value={value}
        onValueChange={setValue}
      >
        {({ visibleDate }) => (
          <React.Fragment>
            <header className={styles.Header}>
              <Calendar.DecrementMonth className={styles.DecrementMonth}>
                <ChevronLeftIcon />
              </Calendar.DecrementMonth>
              <span className={styles.HeaderLabel}>{format(visibleDate, 'MMMM yyyy')}</span>
              <Calendar.IncrementMonth className={styles.IncrementMonth}>
                <ChevronRightIcon />
              </Calendar.IncrementMonth>
            </header>
            <Calendar.DayGrid className={styles.DayGrid}>
              <Calendar.DayGridHeader className={styles.DayGridHeader}>
                <Calendar.DayGridHeaderRow className={styles.DayGridHeaderRow}>
                  {(day) => (
                    <Calendar.DayGridHeaderCell
                      value={day}
                      key={day.getTime()}
                      className={styles.DayGridHeaderCell}
                    />
                  )}
                </Calendar.DayGridHeaderRow>
              </Calendar.DayGridHeader>
              <Calendar.DayGridBody className={styles.DayGridBody}>
                {(week) => (
                  <Calendar.DayGridRow
                    value={week}
                    key={week.getTime()}
                    className={styles.DayGridRow}
                  >
                    {(day) => (
                      <Calendar.DayGridCell
                        value={day}
                        key={day.getTime()}
                        className={styles.DayGridCell}
                      >
                        <Calendar.DayButton className={styles.DayButton} />
                      </Calendar.DayGridCell>
                    )}
                  </Calendar.DayGridRow>
                )}
              </Calendar.DayGridBody>
            </Calendar.DayGrid>
          </React.Fragment>
        )}
      </Calendar.Root>
      {value && <p className={indexStyles.Text}>Stored date: {value.toString()}</p>}
    </div>
  );
}

function ChevronLeftIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m15 18-6-6 6-6" />
    </svg>
  );
}

function ChevronRightIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m9 18 6-6-6-6" />
    </svg>
  );
}
```

```css
/* calendar.module.css */
.Root {
  border: 1px solid var(--calendar-root-border-color);
  border-radius: 8px;
  height: 312px;
  display: flex;
  flex-direction: column;

  --calendar-root-color: var(--color-gray-900);
  --calendar-root-border-color: var(--color-gray-500);
  --calendar-button-hover-bg-color: var(--color-gray-100);
  --calendar-button-focus-border-color: var(--color-blue);
  --calendar-day-grid-separator-bg-color: var(--color-gray-400);
  --calendar-day-grid-header-color: var(--color-gray-500);

  --calendar-cell-selected-bg-color: var(--color-gray-900);
  --calendar-cell-selected-color: var(--color-gray-50);
  --calendar-cell-outside-month-color: var(--color-gray-400);
  --calendar-cell-disabled-color: var(--color-gray-500);
  --calendar-cell-current-border-color: var(--color-gray-500);
  --calendar-cell-unavailable-color: var(--color-red);
}

.Header {
  box-sizing: border-box;
  padding: 8px 12px;
  height: 40px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.HeaderLabel {
  color: var(--calendar-root-color);
}

.DecrementMonth,
.IncrementMonth {
  border: none;
  -webkit-user-select: none;
  user-select: none;
  background-color: transparent;
  border-radius: 4px;
  color: var(--calendar-root-color);
  margin: 0 6px;
  padding: 0;
  display: flex;

  @media (hover: hover) {
    &:hover {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &:focus-visible {
    outline: 2px solid var(--calendar-button-focus-border-color);
  }

  &[data-disabled] {
    pointer-events: none;
    color: var(--calendar-cell-disabled-color);
  }
}

.DayGrid {
  padding: 12px;
  height: 276px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 1;
  position: relative;
}

.DayGridBody {
  display: flex;
  flex-direction: column;
  row-gap: 2px;
}

.DayGridRow,
.DayGridHeaderRow {
  display: flex;
  justify-content: center;
}

.DayGridHeaderCell {
  width: 36px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--calendar-day-grid-header-color);
  font-weight: 700;
  padding: 0;
}

.DayGridCell {
  padding: 0;
}

.DayButton {
  background: none;
  padding: 0;
  font: inherit;
  height: 36px;
  width: 36px;
  position: relative;
  user-select: none;
  border: none;
  background-color: transparent;
  outline: none;
  box-sizing: border-box;
  border-radius: 4px;
  color: var(--calendar-root-color);

  &::before {
    content: '';
    position: absolute;
    inset: 2px;
    border-radius: 4px;
    border: none;
    z-index: -1;
    background-color: transparent;
  }

  &::after {
    content: '';
    border-radius: 4px;
    position: absolute;
    inset: 2px;
  }

  &:not([data-outside-month]):focus-visible {
    &::after {
      outline: 2px solid var(--calendar-button-focus-border-color);
    }
  }

  @media (hover: hover) {
    &:not([data-selected]):hover::before {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &[data-selected]:not([data-outside-month]) {
    color: var(--calendar-cell-selected-color);
  }

  &[data-selected]:not([data-outside-month])::before {
    background-color: var(--calendar-cell-selected-bg-color);
  }

  &[data-disabled] {
    pointer-events: none;
  }

  &:not([data-outside-month])[data-disabled] {
    color: var(--calendar-cell-disabled-color);
  }

  &:not([data-outside-month])[data-invalid] {
    text-decoration: line-through;
  }

  &[data-outside-month] {
    color: var(--calendar-cell-outside-month-color);
    pointer-events: none;
  }

  &[data-current]:not([data-selected], :focus-visible)::after {
    outline: 1px solid var(--calendar-cell-current-border-color);
  }

  &:not([data-disabled], [data-outside-month])[data-unavailable] {
    text-decoration: line-through;
    color: var(--calendar-cell-unavailable-color);
  }
}
```

The calendar can display the date in a selected timezone.

## Demo

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.Wrapper {
  display: flex;
  flex-flow: column wrap;
  gap: 16px;
}

.Select {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  height: 2.5rem;
  padding-left: 0.875rem;
  padding-right: 0.75rem;
  margin: 0;
  outline: 0;
  border: 1px solid var(--color-gray-200);
  border-radius: 0.375rem;
  background-color: canvas;
  font-family: inherit;
  font-size: 1rem;
  line-height: 1.5rem;
  color: var(--color-gray-900);
  -webkit-user-select: none;
  user-select: none;
  min-width: 10rem;

  @media (hover: hover) {
    &:hover {
      background-color: var(--color-gray-100);
    }
  }

  &[data-popup-open] {
    background-color: var(--color-gray-100);
  }

  &:focus-visible {
    outline: 2px solid var(--color-blue);
    outline-offset: -1px;
  }
}

.SelectIcon {
  display: flex;
}

.Positioner {
  outline: none;
  z-index: 1;
  -webkit-user-select: none;
  user-select: none;
}

.Popup {
  box-sizing: border-box;
  border-radius: 0.375rem;
  background-color: canvas;
  background-clip: padding-box;
  color: var(--color-gray-900);
  min-width: var(--anchor-width);
  transform-origin: var(--transform-origin);
  transition:
    transform 150ms,
    opacity 150ms;

  &[data-starting-style],
  &[data-ending-style] {
    opacity: 0;
    transform: scale(0.9);
  }

  &[data-side='none'] {
    transition: none;
    transform: none;
    opacity: 1;
    min-width: calc(var(--anchor-width) + 1rem);
  }

  @media (prefers-color-scheme: light) {
    outline: 1px solid var(--color-gray-200);
    box-shadow:
      0 10px 15px -3px var(--color-gray-200),
      0 4px 6px -4px var(--color-gray-200);
  }

  @media (prefers-color-scheme: dark) {
    outline: 1px solid var(--color-gray-300);
  }
}

.List {
  box-sizing: border-box;
  position: relative;
  padding-block: 0.25rem;
  overflow-y: auto;
  max-height: var(--available-height);
  scroll-padding-block: 1.5rem;
}

.Item {
  box-sizing: border-box;
  outline: 0;
  font-size: 0.875rem;
  line-height: 1rem;
  padding-block: 0.5rem;
  padding-left: 0.625rem;
  padding-right: 1rem;
  display: grid;
  gap: 0.5rem;
  align-items: center;
  grid-template-columns: 0.75rem 1fr;
  cursor: default;
  -webkit-user-select: none;
  user-select: none;

  @media (pointer: coarse) {
    padding-block: 0.625rem;
    font-size: 0.925rem;
  }

  [data-side='none'] & {
    font-size: 1rem;
    padding-right: 3rem;
  }

  &[data-highlighted] {
    z-index: 0;
    position: relative;
    color: var(--color-gray-50);
  }

  &[data-highlighted]::before {
    content: '';
    z-index: -1;
    position: absolute;
    inset-block: 0;
    inset-inline: 0.25rem;
    border-radius: 0.25rem;
    background-color: var(--color-gray-900);
  }
}

.ItemIndicator {
  grid-column-start: 1;
}

.ItemIndicatorIcon {
  display: block;
  width: 0.75rem;
  height: 0.75rem;
}

.ItemText {
  grid-column-start: 2;
}

.ScrollArrow {
  width: 100%;
  background: canvas;
  z-index: 1;
  text-align: center;
  cursor: default;
  border-radius: 0.375rem;
  height: 1rem;
  font-size: 0.75rem;
  display: flex;
  align-items: center;
  justify-content: center;

  &::before {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
  }

  &[data-direction='up'] {
    &[data-side='none'] {
      &::before {
        top: -100%;
      }
    }
  }

  &[data-direction='down'] {
    bottom: 0;

    &[data-side='none'] {
      &::before {
        bottom: -100%;
      }
    }
  }
}
```

```tsx
/* index.tsx */
'use client';
import * as React from 'react';
import { format } from 'date-fns/format';
import { Calendar } from '@base-ui/react/calendar';
import { Select } from '@base-ui/react/select';
import styles from './calendar.module.css';
import indexStyles from './index.module.css';

export default function CalendarWithTimezoneDisplay() {
  const [timezone, setTimezone] = React.useState<Timezone | null>('Australia/Sydney');
  return (
    <div className={indexStyles.Wrapper}>
      <TimezoneSelect
        value={timezone}
        onValueChange={(value) => setTimezone(value as Timezone | null)}
      />
      <Calendar.Root className={styles.Root} timezone={timezone ?? undefined}>
        {({ visibleDate }) => (
          <React.Fragment>
            <header className={styles.Header}>
              <Calendar.DecrementMonth className={styles.DecrementMonth}>
                <ChevronLeftIcon />
              </Calendar.DecrementMonth>
              <span className={styles.HeaderLabel}>{format(visibleDate, 'MMMM yyyy')}</span>
              <Calendar.IncrementMonth className={styles.IncrementMonth}>
                <ChevronRightIcon />
              </Calendar.IncrementMonth>
            </header>
            <Calendar.DayGrid className={styles.DayGrid}>
              <Calendar.DayGridHeader className={styles.DayGridHeader}>
                <Calendar.DayGridHeaderRow className={styles.DayGridHeaderRow}>
                  {(day) => (
                    <Calendar.DayGridHeaderCell
                      value={day}
                      key={day.getTime()}
                      className={styles.DayGridHeaderCell}
                    />
                  )}
                </Calendar.DayGridHeaderRow>
              </Calendar.DayGridHeader>
              <Calendar.DayGridBody className={styles.DayGridBody}>
                {(week) => (
                  <Calendar.DayGridRow
                    value={week}
                    key={week.getTime()}
                    className={styles.DayGridRow}
                  >
                    {(day) => (
                      <Calendar.DayGridCell
                        value={day}
                        key={day.getTime()}
                        className={styles.DayGridCell}
                      >
                        <Calendar.DayButton className={styles.DayButton} />
                      </Calendar.DayGridCell>
                    )}
                  </Calendar.DayGridRow>
                )}
              </Calendar.DayGridBody>
            </Calendar.DayGrid>
          </React.Fragment>
        )}
      </Calendar.Root>
    </div>
  );
}

function TimezoneSelect(props: Omit<Select.Root.Props<string, false>, 'children'>) {
  return (
    <Select.Root {...props}>
      <Select.Trigger className={indexStyles.Select}>
        <Select.Value placeholder="Select timezone" />
        <Select.Icon className={indexStyles.SelectIcon}>
          <ChevronUpDownIcon />
        </Select.Icon>
      </Select.Trigger>
      <Select.Portal>
        <Select.Positioner className={indexStyles.Positioner} sideOffset={8}>
          <Select.Popup className={indexStyles.Popup}>
            <Select.ScrollUpArrow className={indexStyles.ScrollArrow} />
            <Select.List className={indexStyles.List}>
              {timezones.map((timezone) => (
                <Select.Item key={timezone} value={timezone} className={indexStyles.Item}>
                  <Select.ItemIndicator className={indexStyles.ItemIndicator}>
                    <CheckIcon className={indexStyles.ItemIndicatorIcon} />
                  </Select.ItemIndicator>
                  <Select.ItemText className={indexStyles.ItemText}>{timezone}</Select.ItemText>
                </Select.Item>
              ))}
            </Select.List>
            <Select.ScrollDownArrow className={indexStyles.ScrollArrow} />
          </Select.Popup>
        </Select.Positioner>
      </Select.Portal>
    </Select.Root>
  );
}

type Timezone = (typeof timezones)[number];

const timezones = [
  'America/Los_Angeles',
  'Europe/Paris',
  'Asia/Tokyo',
  'Australia/Sydney',
] as const;

function ChevronUpDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="8"
      height="12"
      viewBox="0 0 8 12"
      fill="none"
      stroke="currentcolor"
      strokeWidth="1.5"
      {...props}
    >
      <path d="M0.5 4.5L4 1.5L7.5 4.5" />
      <path d="M0.5 7.5L4 10.5L7.5 7.5" />
    </svg>
  );
}

function CheckIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg fill="currentcolor" width="10" height="10" viewBox="0 0 10 10" {...props}>
      <path d="M9.1603 1.12218C9.50684 1.34873 9.60427 1.81354 9.37792 2.16038L5.13603 8.66012C5.01614 8.8438 4.82192 8.96576 4.60451 8.99384C4.3871 9.02194 4.1683 8.95335 4.00574 8.80615L1.24664 6.30769C0.939709 6.02975 0.916013 5.55541 1.19372 5.24822C1.47142 4.94102 1.94536 4.91731 2.2523 5.19524L4.36085 7.10461L8.12299 1.33999C8.34934 0.993152 8.81376 0.895638 9.1603 1.12218Z" />
    </svg>
  );
}

function ChevronLeftIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m15 18-6-6 6-6" />
    </svg>
  );
}

function ChevronRightIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m9 18 6-6-6-6" />
    </svg>
  );
}
```

```css
/* calendar.module.css */
.Root {
  border: 1px solid var(--calendar-root-border-color);
  border-radius: 8px;
  height: 312px;
  display: flex;
  flex-direction: column;

  --calendar-root-color: var(--color-gray-900);
  --calendar-root-border-color: var(--color-gray-500);
  --calendar-button-hover-bg-color: var(--color-gray-100);
  --calendar-button-focus-border-color: var(--color-blue);
  --calendar-day-grid-separator-bg-color: var(--color-gray-400);
  --calendar-day-grid-header-color: var(--color-gray-500);

  --calendar-cell-selected-bg-color: var(--color-gray-900);
  --calendar-cell-selected-color: var(--color-gray-50);
  --calendar-cell-outside-month-color: var(--color-gray-400);
  --calendar-cell-disabled-color: var(--color-gray-500);
  --calendar-cell-current-border-color: var(--color-gray-500);
  --calendar-cell-unavailable-color: var(--color-red);
}

.Header {
  box-sizing: border-box;
  padding: 8px 12px;
  height: 40px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.HeaderLabel {
  color: var(--calendar-root-color);
}

.DecrementMonth,
.IncrementMonth {
  border: none;
  -webkit-user-select: none;
  user-select: none;
  background-color: transparent;
  border-radius: 4px;
  color: var(--calendar-root-color);
  margin: 0 6px;
  padding: 0;
  display: flex;

  @media (hover: hover) {
    &:hover {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &:focus-visible {
    outline: 2px solid var(--calendar-button-focus-border-color);
  }

  &[data-disabled] {
    pointer-events: none;
    color: var(--calendar-cell-disabled-color);
  }
}

.DayGrid {
  padding: 12px;
  height: 276px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 1;
  position: relative;
}

.DayGridBody {
  display: flex;
  flex-direction: column;
  row-gap: 2px;
}

.DayGridRow,
.DayGridHeaderRow {
  display: flex;
  justify-content: center;
}

.DayGridHeaderCell {
  width: 36px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--calendar-day-grid-header-color);
  font-weight: 700;
  padding: 0;
}

.DayGridCell {
  padding: 0;
}

.DayButton {
  background: none;
  padding: 0;
  font: inherit;
  height: 36px;
  width: 36px;
  position: relative;
  user-select: none;
  border: none;
  background-color: transparent;
  outline: none;
  box-sizing: border-box;
  border-radius: 4px;
  color: var(--calendar-root-color);

  &::before {
    content: '';
    position: absolute;
    inset: 2px;
    border-radius: 4px;
    border: none;
    z-index: -1;
    background-color: transparent;
  }

  &::after {
    content: '';
    border-radius: 4px;
    position: absolute;
    inset: 2px;
  }

  &:not([data-outside-month]):focus-visible {
    &::after {
      outline: 2px solid var(--calendar-button-focus-border-color);
    }
  }

  @media (hover: hover) {
    &:not([data-selected]):hover::before {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &[data-selected]:not([data-outside-month]) {
    color: var(--calendar-cell-selected-color);
  }

  &[data-selected]:not([data-outside-month])::before {
    background-color: var(--calendar-cell-selected-bg-color);
  }

  &[data-disabled] {
    pointer-events: none;
  }

  &:not([data-outside-month])[data-disabled] {
    color: var(--calendar-cell-disabled-color);
  }

  &:not([data-outside-month])[data-invalid] {
    text-decoration: line-through;
  }

  &[data-outside-month] {
    color: var(--calendar-cell-outside-month-color);
    pointer-events: none;
  }

  &[data-current]:not([data-selected], :focus-visible)::after {
    outline: 1px solid var(--calendar-cell-current-border-color);
  }

  &:not([data-disabled], [data-outside-month])[data-unavailable] {
    text-decoration: line-through;
    color: var(--calendar-cell-unavailable-color);
  }
}
```

### Month and year select

Use `Calendar.useContext()` inside the calendar to read `visibleDate` and call `setVisibleDate`, enabling custom controls like the [Select](/react/components/select.md) component for direct month and year navigation.

## Demo

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.HeaderSelectWrapper {
  display: flex;
  flex: 1;
  justify-content: space-between;
}

.Select {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.3rem;
  height: 1.75rem;
  padding-left: 0.5rem;
  padding-right: 0.375rem;
  margin: 0;
  outline: 0;
  border: 1px solid var(--color-gray-200);
  border-radius: 0.375rem;
  background-color: canvas;
  font-family: inherit;
  font-size: 1rem;
  line-height: 1.25rem;
  color: var(--color-gray-900);
  -webkit-user-select: none;
  user-select: none;

  @media (hover: hover) {
    &:hover {
      background-color: var(--color-gray-100);
    }
  }

  &[data-popup-open] {
    background-color: var(--color-gray-100);
  }

  &:focus-visible {
    outline: 2px solid var(--color-blue);
    outline-offset: -1px;
  }

  &[data-month-select] {
    min-width: 6.854rem;
  }
}

.SelectIcon {
  display: flex;
}

.Positioner {
  outline: none;
  z-index: 1;
  -webkit-user-select: none;
  user-select: none;
}

.Popup {
  box-sizing: border-box;
  border-radius: 0.375rem;
  background-color: canvas;
  background-clip: padding-box;
  color: var(--color-gray-900);
  min-width: var(--anchor-width);
  transform-origin: var(--transform-origin);
  transition:
    transform 150ms,
    opacity 150ms;

  &[data-starting-style],
  &[data-ending-style] {
    opacity: 0;
    transform: scale(0.9);
  }

  &[data-side='none'] {
    transition: none;
    transform: none;
    opacity: 1;
    min-width: calc(var(--anchor-width) + 1rem);
  }

  @media (prefers-color-scheme: light) {
    outline: 1px solid var(--color-gray-200);
    box-shadow:
      0 10px 15px -3px var(--color-gray-200),
      0 4px 6px -4px var(--color-gray-200);
  }

  @media (prefers-color-scheme: dark) {
    outline: 1px solid var(--color-gray-300);
  }
}

.List {
  box-sizing: border-box;
  position: relative;
  padding-block: 0.25rem;
  overflow-y: auto;
  max-height: var(--available-height);
  scroll-padding-block: 1.5rem;
}

.Item {
  box-sizing: border-box;
  outline: 0;
  font-size: 0.875rem;
  line-height: 1rem;
  padding-block: 0.5rem;
  padding-left: 0.625rem;
  padding-right: 1rem;
  display: grid;
  gap: 0.5rem;
  align-items: center;
  grid-template-columns: 0.75rem 1fr;
  cursor: default;
  -webkit-user-select: none;
  user-select: none;

  @media (pointer: coarse) {
    padding-block: 0.625rem;
    font-size: 0.925rem;
  }

  [data-side='none'] & {
    font-size: 1rem;
    padding-right: 3rem;
  }

  &[data-highlighted] {
    z-index: 0;
    position: relative;
    color: var(--color-gray-50);
  }

  &[data-highlighted]::before {
    content: '';
    z-index: -1;
    position: absolute;
    inset-block: 0;
    inset-inline: 0.25rem;
    border-radius: 0.25rem;
    background-color: var(--color-gray-900);
  }
}

.ItemIndicator {
  grid-column-start: 1;
}

.ItemIndicatorIcon {
  display: block;
  width: 0.75rem;
  height: 0.75rem;
}

.ItemText {
  grid-column-start: 2;
}

.ScrollArrow {
  width: 100%;
  background: canvas;
  z-index: 1;
  text-align: center;
  cursor: default;
  border-radius: 0.375rem;
  height: 1rem;
  font-size: 0.75rem;
  display: flex;
  align-items: center;
  justify-content: center;

  &::before {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
  }

  &[data-direction='up'] {
    &[data-side='none'] {
      &::before {
        top: -100%;
      }
    }
  }

  &[data-direction='down'] {
    bottom: 0;

    &[data-side='none'] {
      &::before {
        bottom: -100%;
      }
    }
  }
}
```

```tsx
/* index.tsx */
'use client';
import * as React from 'react';
import { format } from 'date-fns/format';
import { getMonth } from 'date-fns/getMonth';
import { getYear } from 'date-fns/getYear';
import { Calendar } from '@base-ui/react/calendar';
import { Select } from '@base-ui/react/select';
import styles from './calendar.module.css';
import indexStyles from './index.module.css';

const YEAR_PAST = 40;
const YEAR_FUTURE = 10;
const MONTHS = Array.from({ length: 12 }, (_, i) => format(new Date(2000, i, 1), 'MMMM'));

function CalendarContent() {
  const { visibleDate, setVisibleDate } = Calendar.useContext();
  const currentMonth = getMonth(visibleDate);
  const currentYear = getYear(visibleDate);
  const todayYear = getYear(new Date());
  const years = Array.from(
    { length: YEAR_PAST + YEAR_FUTURE + 1 },
    (_, i) => todayYear - YEAR_PAST + i,
  );

  return (
    <React.Fragment>
      <header className={styles.Header}>
        <Calendar.DecrementMonth className={styles.DecrementMonth}>
          <ChevronLeftIcon />
        </Calendar.DecrementMonth>
        <div className={indexStyles.HeaderSelectWrapper}>
          <Select.Root
            value={currentMonth}
            onValueChange={(value, eventDetails) => {
              if (value != null) {
                setVisibleDate(
                  new Date(currentYear, value, 1),
                  eventDetails.event,
                  eventDetails.trigger as HTMLElement,
                  'month-change',
                );
              }
            }}
          >
            <Select.Trigger className={indexStyles.Select} aria-label="Month" data-month-select>
              <Select.Value>{(value: number) => MONTHS[value]}</Select.Value>
              <Select.Icon className={indexStyles.SelectIcon}>
                <ChevronUpDownIcon />
              </Select.Icon>
            </Select.Trigger>
            <Select.Portal>
              <Select.Positioner className={indexStyles.Positioner} sideOffset={8}>
                <Select.Popup className={indexStyles.Popup}>
                  <Select.ScrollUpArrow className={indexStyles.ScrollArrow} />
                  <Select.List className={indexStyles.List}>
                    {MONTHS.map((name, index) => (
                      <Select.Item key={name} value={index} className={indexStyles.Item}>
                        <Select.ItemIndicator className={indexStyles.ItemIndicator}>
                          <CheckIcon className={indexStyles.ItemIndicatorIcon} />
                        </Select.ItemIndicator>
                        <Select.ItemText className={indexStyles.ItemText}>{name}</Select.ItemText>
                      </Select.Item>
                    ))}
                  </Select.List>
                  <Select.ScrollDownArrow className={indexStyles.ScrollArrow} />
                </Select.Popup>
              </Select.Positioner>
            </Select.Portal>
          </Select.Root>
          <Select.Root
            value={currentYear}
            onValueChange={(value, eventDetails) => {
              if (value != null) {
                setVisibleDate(
                  new Date(value, currentMonth, 1),
                  eventDetails.event,
                  eventDetails.trigger as HTMLElement,
                  'month-change',
                );
              }
            }}
          >
            <Select.Trigger className={indexStyles.Select} aria-label="Year">
              <Select.Value />
              <Select.Icon className={indexStyles.SelectIcon}>
                <ChevronUpDownIcon />
              </Select.Icon>
            </Select.Trigger>
            <Select.Portal>
              <Select.Positioner className={indexStyles.Positioner} sideOffset={8}>
                <Select.Popup className={indexStyles.Popup}>
                  <Select.ScrollUpArrow className={indexStyles.ScrollArrow} />
                  <Select.List className={indexStyles.List}>
                    {years.map((year) => (
                      <Select.Item key={year} value={year} className={indexStyles.Item}>
                        <Select.ItemIndicator className={indexStyles.ItemIndicator}>
                          <CheckIcon className={indexStyles.ItemIndicatorIcon} />
                        </Select.ItemIndicator>
                        <Select.ItemText className={indexStyles.ItemText}>{year}</Select.ItemText>
                      </Select.Item>
                    ))}
                  </Select.List>
                  <Select.ScrollDownArrow className={indexStyles.ScrollArrow} />
                </Select.Popup>
              </Select.Positioner>
            </Select.Portal>
          </Select.Root>
        </div>
        <Calendar.IncrementMonth className={styles.IncrementMonth}>
          <ChevronRightIcon />
        </Calendar.IncrementMonth>
      </header>
      <Calendar.DayGrid className={styles.DayGrid}>
        <Calendar.DayGridHeader className={styles.DayGridHeader}>
          <Calendar.DayGridHeaderRow className={styles.DayGridHeaderRow}>
            {(day) => (
              <Calendar.DayGridHeaderCell
                value={day}
                key={day.getTime()}
                className={styles.DayGridHeaderCell}
              />
            )}
          </Calendar.DayGridHeaderRow>
        </Calendar.DayGridHeader>
        <Calendar.DayGridBody className={styles.DayGridBody}>
          {(week) => (
            <Calendar.DayGridRow value={week} key={week.getTime()} className={styles.DayGridRow}>
              {(day) => (
                <Calendar.DayGridCell
                  value={day}
                  key={day.getTime()}
                  className={styles.DayGridCell}
                >
                  <Calendar.DayButton className={styles.DayButton} />
                </Calendar.DayGridCell>
              )}
            </Calendar.DayGridRow>
          )}
        </Calendar.DayGridBody>
      </Calendar.DayGrid>
    </React.Fragment>
  );
}

export default function ExampleCalendarYearMonthSelect() {
  return (
    <Calendar.Root className={styles.Root}>
      <CalendarContent />
    </Calendar.Root>
  );
}

function ChevronUpDownIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="8"
      height="12"
      viewBox="0 0 8 12"
      fill="none"
      stroke="currentcolor"
      strokeWidth="1.5"
      {...props}
    >
      <path d="M0.5 4.5L4 1.5L7.5 4.5" />
      <path d="M0.5 7.5L4 10.5L7.5 7.5" />
    </svg>
  );
}

function CheckIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg fill="currentcolor" width="10" height="10" viewBox="0 0 10 10" {...props}>
      <path d="M9.1603 1.12218C9.50684 1.34873 9.60427 1.81354 9.37792 2.16038L5.13603 8.66012C5.01614 8.8438 4.82192 8.96576 4.60451 8.99384C4.3871 9.02194 4.1683 8.95335 4.00574 8.80615L1.24664 6.30769C0.939709 6.02975 0.916013 5.55541 1.19372 5.24822C1.47142 4.94102 1.94536 4.91731 2.2523 5.19524L4.36085 7.10461L8.12299 1.33999C8.34934 0.993152 8.81376 0.895638 9.1603 1.12218Z" />
    </svg>
  );
}

function ChevronLeftIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m15 18-6-6 6-6" />
    </svg>
  );
}

function ChevronRightIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m9 18 6-6-6-6" />
    </svg>
  );
}
```

```css
/* calendar.module.css */
.Root {
  border: 1px solid var(--calendar-root-border-color);
  border-radius: 8px;
  height: 312px;
  display: flex;
  flex-direction: column;

  --calendar-root-color: var(--color-gray-900);
  --calendar-root-border-color: var(--color-gray-500);
  --calendar-button-hover-bg-color: var(--color-gray-100);
  --calendar-button-focus-border-color: var(--color-blue);
  --calendar-day-grid-separator-bg-color: var(--color-gray-400);
  --calendar-day-grid-header-color: var(--color-gray-500);

  --calendar-cell-selected-bg-color: var(--color-gray-900);
  --calendar-cell-selected-color: var(--color-gray-50);
  --calendar-cell-outside-month-color: var(--color-gray-400);
  --calendar-cell-disabled-color: var(--color-gray-500);
  --calendar-cell-current-border-color: var(--color-gray-500);
  --calendar-cell-unavailable-color: var(--color-red);
}

.Header {
  box-sizing: border-box;
  padding: 8px 12px;
  height: 40px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.HeaderLabel {
  color: var(--calendar-root-color);
}

.DecrementMonth,
.IncrementMonth {
  border: none;
  -webkit-user-select: none;
  user-select: none;
  background-color: transparent;
  border-radius: 4px;
  color: var(--calendar-root-color);
  margin: 0 6px;
  padding: 0;
  display: flex;

  @media (hover: hover) {
    &:hover {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &:focus-visible {
    outline: 2px solid var(--calendar-button-focus-border-color);
  }

  &[data-disabled] {
    pointer-events: none;
    color: var(--calendar-cell-disabled-color);
  }
}

.DayGrid {
  padding: 12px;
  height: 276px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 1;
  position: relative;
}

.DayGridBody {
  display: flex;
  flex-direction: column;
  row-gap: 2px;
}

.DayGridRow,
.DayGridHeaderRow {
  display: flex;
  justify-content: center;
}

.DayGridHeaderCell {
  width: 36px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--calendar-day-grid-header-color);
  font-weight: 700;
  padding: 0;
}

.DayGridCell {
  padding: 0;
}

.DayButton {
  background: none;
  padding: 0;
  font: inherit;
  height: 36px;
  width: 36px;
  position: relative;
  user-select: none;
  border: none;
  background-color: transparent;
  outline: none;
  box-sizing: border-box;
  border-radius: 4px;
  color: var(--calendar-root-color);

  &::before {
    content: '';
    position: absolute;
    inset: 2px;
    border-radius: 4px;
    border: none;
    z-index: -1;
    background-color: transparent;
  }

  &::after {
    content: '';
    border-radius: 4px;
    position: absolute;
    inset: 2px;
  }

  &:not([data-outside-month]):focus-visible {
    &::after {
      outline: 2px solid var(--calendar-button-focus-border-color);
    }
  }

  @media (hover: hover) {
    &:not([data-selected]):hover::before {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &[data-selected]:not([data-outside-month]) {
    color: var(--calendar-cell-selected-color);
  }

  &[data-selected]:not([data-outside-month])::before {
    background-color: var(--calendar-cell-selected-bg-color);
  }

  &[data-disabled] {
    pointer-events: none;
  }

  &:not([data-outside-month])[data-disabled] {
    color: var(--calendar-cell-disabled-color);
  }

  &:not([data-outside-month])[data-invalid] {
    text-decoration: line-through;
  }

  &[data-outside-month] {
    color: var(--calendar-cell-outside-month-color);
    pointer-events: none;
  }

  &[data-current]:not([data-selected], :focus-visible)::after {
    outline: 1px solid var(--calendar-cell-current-border-color);
  }

  &:not([data-disabled], [data-outside-month])[data-unavailable] {
    text-decoration: line-through;
    color: var(--calendar-cell-unavailable-color);
  }
}
```

### Animating month changes

You can use the `<Calendar.Viewport>` component to animate month transitions.
Wrapping the `<Calendar.DayGridBody>` in the `<Calendar.Viewport>` renders the previous month if a transition is in progress.

## Demo

### CSS Modules

This example shows how to implement the component using CSS Modules.

```css
/* index.module.css */
.Root {
  /* Clip overflow to prevent content spilling out when transitioning. */
  overflow: clip;
  --duration: 0.2s;
  --easing: cubic-bezier(0.22, 1, 0.36, 1);
}

.HeaderLabelWrapper {
  width: 100%;
  display: grid;
  justify-content: center;
}

.HeaderLabel {
  grid-row: 1;
  grid-column: 1;
  background-color: var(--color-background);
  min-width: 185px;
  text-align: center;
  overflow: clip;
  /* Apply transition only when `data-ending-style` is present to allow for smooth animations from original translated positions. */
  &[data-ending-style] {
    &[data-current],
    &[data-previous] {
      @media (prefers-reduced-motion: no-preference) {
        transition:
          opacity var(--duration) var(--easing),
          transform var(--duration) var(--easing);
      }
    }
  }

  &[data-navigation-direction='next'][data-previous] {
    &[data-starting-style] {
      opacity: 1;
      transform: translateY(0);
    }
    &[data-ending-style] {
      opacity: 0;
      transform: translateY(-20px);
    }
  }

  &[data-navigation-direction='next'][data-current] {
    &[data-starting-style] {
      opacity: 0;
      transform: translateY(20px);
    }
    &[data-ending-style] {
      opacity: 1;
      transform: translateY(0);
    }
  }

  &[data-navigation-direction='previous'][data-previous] {
    &[data-starting-style] {
      opacity: 1;
      transform: translateY(0);
    }
    &[data-ending-style] {
      opacity: 0;
      transform: translateY(20px);
    }
  }

  &[data-navigation-direction='previous'][data-current] {
    &[data-starting-style] {
      opacity: 0;
      transform: translateY(-20px);
    }
    &[data-ending-style] {
      opacity: 1;
      transform: translateY(0);
    }
  }
}

.DayGrid {
  /* Need to use grid to position two tbody elements centered horizontally. */
  display: grid;
  grid-template-rows: min-content 1fr;
  grid-template-columns: 1fr;
}

.DayGridBody {
  grid-row: 2;
  grid-column: 1;
  transform: translateX(0);
  opacity: 1;

  /* Apply transition only when `data-ending-style` is present to allow for smooth animations from original translated positions. */
  &[data-ending-style] {
    &[data-current],
    &[data-previous] {
      @media (prefers-reduced-motion: no-preference) {
        transition:
          opacity var(--duration) var(--easing),
          transform var(--duration) var(--easing);
      }
    }
  }

  &[data-navigation-direction='next'][data-previous] {
    &[data-starting-style] {
      transform: translateX(0);
      opacity: 1;
    }
    &[data-ending-style] {
      transform: translateX(-100%);
      opacity: 0;
    }
  }

  &[data-navigation-direction='next'][data-current] {
    &[data-starting-style] {
      transform: translateX(100%);
      opacity: 0;
    }
    &[data-ending-style] {
      transform: translateX(0);
      opacity: 1;
    }
  }

  &[data-navigation-direction='previous'][data-previous] {
    &[data-starting-style] {
      transform: translateX(0);
      opacity: 1;
    }
    &[data-ending-style] {
      transform: translateX(100%);
      opacity: 0;
    }
  }

  &[data-navigation-direction='previous'][data-current] {
    &[data-starting-style] {
      transform: translateX(-100%);
      opacity: 0;
    }
    &[data-ending-style] {
      transform: translateX(0);
      opacity: 1;
    }
  }
}
```

```tsx
/* index.tsx */
'use client';
import * as React from 'react';
import clsx from 'clsx';
import { format } from 'date-fns/format';
import { Calendar } from '@base-ui/react/calendar';
import styles from './calendar.module.css';
import indexStyles from './index.module.css';

export default function AnimatedCalendar() {
  return (
    <Calendar.Root className={clsx(styles.Root, indexStyles.Root)}>
      {({ visibleDate }) => (
        <React.Fragment>
          <header className={styles.Header}>
            <Calendar.DecrementMonth className={styles.DecrementMonth}>
              <ChevronLeftIcon />
            </Calendar.DecrementMonth>
            <div className={indexStyles.HeaderLabelWrapper}>
              <Calendar.Viewport>
                <span className={clsx(styles.HeaderLabel, indexStyles.HeaderLabel)}>
                  {format(visibleDate, 'MMMM yyyy')}
                </span>
              </Calendar.Viewport>
            </div>
            <Calendar.IncrementMonth className={styles.IncrementMonth}>
              <ChevronRightIcon />
            </Calendar.IncrementMonth>
          </header>
          <Calendar.DayGrid className={clsx(styles.DayGrid, indexStyles.DayGrid)}>
            <Calendar.DayGridHeader className={styles.DayGridHeader}>
              <Calendar.DayGridHeaderRow className={styles.DayGridHeaderRow}>
                {(day) => (
                  <Calendar.DayGridHeaderCell
                    value={day}
                    key={day.getTime()}
                    className={styles.DayGridHeaderCell}
                  />
                )}
              </Calendar.DayGridHeaderRow>
            </Calendar.DayGridHeader>
            <Calendar.Viewport>
              <Calendar.DayGridBody className={clsx(styles.DayGridBody, indexStyles.DayGridBody)}>
                {(week) => (
                  <Calendar.DayGridRow
                    value={week}
                    key={week.getTime()}
                    className={styles.DayGridRow}
                  >
                    {(day) => (
                      <Calendar.DayGridCell
                        value={day}
                        key={day.getTime()}
                        className={styles.DayGridCell}
                      >
                        <Calendar.DayButton className={styles.DayButton} />
                      </Calendar.DayGridCell>
                    )}
                  </Calendar.DayGridRow>
                )}
              </Calendar.DayGridBody>
            </Calendar.Viewport>
          </Calendar.DayGrid>
        </React.Fragment>
      )}
    </Calendar.Root>
  );
}

function ChevronLeftIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m15 18-6-6 6-6" />
    </svg>
  );
}

function ChevronRightIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m9 18 6-6-6-6" />
    </svg>
  );
}
```

```css
/* calendar.module.css */
.Root {
  border: 1px solid var(--calendar-root-border-color);
  border-radius: 8px;
  height: 312px;
  display: flex;
  flex-direction: column;

  --calendar-root-color: var(--color-gray-900);
  --calendar-root-border-color: var(--color-gray-500);
  --calendar-button-hover-bg-color: var(--color-gray-100);
  --calendar-button-focus-border-color: var(--color-blue);
  --calendar-day-grid-separator-bg-color: var(--color-gray-400);
  --calendar-day-grid-header-color: var(--color-gray-500);

  --calendar-cell-selected-bg-color: var(--color-gray-900);
  --calendar-cell-selected-color: var(--color-gray-50);
  --calendar-cell-outside-month-color: var(--color-gray-400);
  --calendar-cell-disabled-color: var(--color-gray-500);
  --calendar-cell-current-border-color: var(--color-gray-500);
  --calendar-cell-unavailable-color: var(--color-red);
}

.Header {
  box-sizing: border-box;
  padding: 8px 12px;
  height: 40px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.HeaderLabel {
  color: var(--calendar-root-color);
}

.DecrementMonth,
.IncrementMonth {
  border: none;
  -webkit-user-select: none;
  user-select: none;
  background-color: transparent;
  border-radius: 4px;
  color: var(--calendar-root-color);
  margin: 0 6px;
  padding: 0;
  display: flex;

  @media (hover: hover) {
    &:hover {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &:focus-visible {
    outline: 2px solid var(--calendar-button-focus-border-color);
  }

  &[data-disabled] {
    pointer-events: none;
    color: var(--calendar-cell-disabled-color);
  }
}

.DayGrid {
  padding: 12px;
  height: 276px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 1;
  position: relative;
}

.DayGridBody {
  display: flex;
  flex-direction: column;
  row-gap: 2px;
}

.DayGridRow,
.DayGridHeaderRow {
  display: flex;
  justify-content: center;
}

.DayGridHeaderCell {
  width: 36px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--calendar-day-grid-header-color);
  font-weight: 700;
  padding: 0;
}

.DayGridCell {
  padding: 0;
}

.DayButton {
  background: none;
  padding: 0;
  font: inherit;
  height: 36px;
  width: 36px;
  position: relative;
  user-select: none;
  border: none;
  background-color: transparent;
  outline: none;
  box-sizing: border-box;
  border-radius: 4px;
  color: var(--calendar-root-color);

  &::before {
    content: '';
    position: absolute;
    inset: 2px;
    border-radius: 4px;
    border: none;
    z-index: -1;
    background-color: transparent;
  }

  &::after {
    content: '';
    border-radius: 4px;
    position: absolute;
    inset: 2px;
  }

  &:not([data-outside-month]):focus-visible {
    &::after {
      outline: 2px solid var(--calendar-button-focus-border-color);
    }
  }

  @media (hover: hover) {
    &:not([data-selected]):hover::before {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &[data-selected]:not([data-outside-month]) {
    color: var(--calendar-cell-selected-color);
  }

  &[data-selected]:not([data-outside-month])::before {
    background-color: var(--calendar-cell-selected-bg-color);
  }

  &[data-disabled] {
    pointer-events: none;
  }

  &:not([data-outside-month])[data-disabled] {
    color: var(--calendar-cell-disabled-color);
  }

  &:not([data-outside-month])[data-invalid] {
    text-decoration: line-through;
  }

  &[data-outside-month] {
    color: var(--calendar-cell-outside-month-color);
    pointer-events: none;
  }

  &[data-current]:not([data-selected], :focus-visible)::after {
    outline: 1px solid var(--calendar-cell-current-border-color);
  }

  &:not([data-disabled], [data-outside-month])[data-unavailable] {
    text-decoration: line-through;
    color: var(--calendar-cell-unavailable-color);
  }
}
```

#### Animating with `motion/react`

You can use external animation libraries like [Framer Motion](https://www.framer.com/motion/) to animate month transitions.

## Demo

### CSS Modules

This example shows how to implement the component using CSS Modules.

```tsx
/* index.tsx */
'use client';
import * as React from 'react';
import { format } from 'date-fns/format';
import { Calendar } from '@base-ui/react/calendar';
import { motion, AnimatePresence } from 'motion/react';
import styles from './calendar.module.css';

export default function AnimatedCalendarWithMotion() {
  return (
    <Calendar.Root className={styles.Root}>
      {({ visibleDate }) => (
        <React.Fragment>
          <header className={styles.Header}>
            <Calendar.DecrementMonth className={styles.DecrementMonth}>
              <ChevronLeftIcon />
            </Calendar.DecrementMonth>
            <AnimatePresence initial={false} mode="popLayout">
              <motion.span layout className={styles.HeaderLabel}>
                {format(visibleDate, 'MMMM yyyy')}
              </motion.span>
            </AnimatePresence>
            <Calendar.IncrementMonth className={styles.IncrementMonth}>
              <ChevronRightIcon />
            </Calendar.IncrementMonth>
          </header>
          <Calendar.DayGrid className={styles.DayGrid}>
            <Calendar.DayGridHeader className={styles.DayGridHeader}>
              <Calendar.DayGridHeaderRow className={styles.DayGridHeaderRow}>
                {(day) => (
                  <Calendar.DayGridHeaderCell
                    value={day}
                    key={day.getTime()}
                    className={styles.DayGridHeaderCell}
                  />
                )}
              </Calendar.DayGridHeaderRow>
            </Calendar.DayGridHeader>
            <AnimatePresence initial={false} mode="popLayout">
              <Calendar.DayGridBody
                key={`${visibleDate.getUTCFullYear()}-${visibleDate.getMonth()}`}
                className={styles.DayGridBody}
                render={
                  <motion.tbody
                    initial={{ opacity: 0, scale: 0 }}
                    animate={{ opacity: 1, scale: 1 }}
                    exit={{ opacity: 0, scale: 0 }}
                  />
                }
              >
                {(week) => (
                  <Calendar.DayGridRow
                    value={week}
                    key={week.getTime()}
                    className={styles.DayGridRow}
                  >
                    {(day) => (
                      <Calendar.DayGridCell
                        value={day}
                        key={day.getTime()}
                        className={styles.DayGridCell}
                      >
                        <Calendar.DayButton className={styles.DayButton} />
                      </Calendar.DayGridCell>
                    )}
                  </Calendar.DayGridRow>
                )}
              </Calendar.DayGridBody>
            </AnimatePresence>
          </Calendar.DayGrid>
        </React.Fragment>
      )}
    </Calendar.Root>
  );
}

function ChevronLeftIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m15 18-6-6 6-6" />
    </svg>
  );
}

function ChevronRightIcon(props: React.ComponentProps<'svg'>) {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentcolor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <path d="m9 18 6-6-6-6" />
    </svg>
  );
}
```

```css
/* calendar.module.css */
.Root {
  border: 1px solid var(--calendar-root-border-color);
  border-radius: 8px;
  height: 312px;
  display: flex;
  flex-direction: column;

  --calendar-root-color: var(--color-gray-900);
  --calendar-root-border-color: var(--color-gray-500);
  --calendar-button-hover-bg-color: var(--color-gray-100);
  --calendar-button-focus-border-color: var(--color-blue);
  --calendar-day-grid-separator-bg-color: var(--color-gray-400);
  --calendar-day-grid-header-color: var(--color-gray-500);

  --calendar-cell-selected-bg-color: var(--color-gray-900);
  --calendar-cell-selected-color: var(--color-gray-50);
  --calendar-cell-outside-month-color: var(--color-gray-400);
  --calendar-cell-disabled-color: var(--color-gray-500);
  --calendar-cell-current-border-color: var(--color-gray-500);
  --calendar-cell-unavailable-color: var(--color-red);
}

.Header {
  box-sizing: border-box;
  padding: 8px 12px;
  height: 40px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.HeaderLabel {
  color: var(--calendar-root-color);
}

.DecrementMonth,
.IncrementMonth {
  border: none;
  -webkit-user-select: none;
  user-select: none;
  background-color: transparent;
  border-radius: 4px;
  color: var(--calendar-root-color);
  margin: 0 6px;
  padding: 0;
  display: flex;

  @media (hover: hover) {
    &:hover {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &:focus-visible {
    outline: 2px solid var(--calendar-button-focus-border-color);
  }

  &[data-disabled] {
    pointer-events: none;
    color: var(--calendar-cell-disabled-color);
  }
}

.DayGrid {
  padding: 12px;
  height: 276px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 1;
  position: relative;
}

.DayGridBody {
  display: flex;
  flex-direction: column;
  row-gap: 2px;
}

.DayGridRow,
.DayGridHeaderRow {
  display: flex;
  justify-content: center;
}

.DayGridHeaderCell {
  width: 36px;
  text-align: center;
  font-size: 0.75rem;
  color: var(--calendar-day-grid-header-color);
  font-weight: 700;
  padding: 0;
}

.DayGridCell {
  padding: 0;
}

.DayButton {
  background: none;
  padding: 0;
  font: inherit;
  height: 36px;
  width: 36px;
  position: relative;
  user-select: none;
  border: none;
  background-color: transparent;
  outline: none;
  box-sizing: border-box;
  border-radius: 4px;
  color: var(--calendar-root-color);

  &::before {
    content: '';
    position: absolute;
    inset: 2px;
    border-radius: 4px;
    border: none;
    z-index: -1;
    background-color: transparent;
  }

  &::after {
    content: '';
    border-radius: 4px;
    position: absolute;
    inset: 2px;
  }

  &:not([data-outside-month]):focus-visible {
    &::after {
      outline: 2px solid var(--calendar-button-focus-border-color);
    }
  }

  @media (hover: hover) {
    &:not([data-selected]):hover::before {
      background-color: var(--calendar-button-hover-bg-color);
    }
  }

  &[data-selected]:not([data-outside-month]) {
    color: var(--calendar-cell-selected-color);
  }

  &[data-selected]:not([data-outside-month])::before {
    background-color: var(--calendar-cell-selected-bg-color);
  }

  &[data-disabled] {
    pointer-events: none;
  }

  &:not([data-outside-month])[data-disabled] {
    color: var(--calendar-cell-disabled-color);
  }

  &:not([data-outside-month])[data-invalid] {
    text-decoration: line-through;
  }

  &[data-outside-month] {
    color: var(--calendar-cell-outside-month-color);
    pointer-events: none;
  }

  &[data-current]:not([data-selected], :focus-visible)::after {
    outline: 1px solid var(--calendar-cell-current-border-color);
  }

  &:not([data-disabled], [data-outside-month])[data-unavailable] {
    text-decoration: line-through;
    color: var(--calendar-cell-unavailable-color);
  }
}
```

### Localization

The calendar's locale is controlled by the date library. It handles month and day names, as well as the start of the week.
You can use the [`<LocalizationProvider>`](/react/utils/localization-provider.md) to customize these settings.

## API reference

### Root

Groups all parts of the calendar.
Renders a `<div>` element.

**Root Props:**

| Prop                | Type                                                                                                       | Default                                                                                 | Description                                                                                                                                                                                                                    |
| :------------------ | :--------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| defaultValue        | `TemporalValue`                                                                                            | -                                                                                       | The uncontrolled value that should be initially selected.&#xA;To render a controlled (Range)Calendar, use the `value` prop instead.                                                                                            |
| value               | `TemporalValue`                                                                                            | -                                                                                       | The controlled value that should be selected.&#xA;To render an uncontrolled (Range)Calendar, use the `defaultValue` prop instead.                                                                                              |
| onValueChange       | `((value: TemporalValue, eventDetails: CalendarValueChangeEventDetails<ValidateDateReturnValue>) => void)` | -                                                                                       | Event handler called when the selected value changes.&#xA;Provides the new value as an argument.&#xA;Has `getValidationError()` in the `eventDetails` to retrieve the validation error associated to the new value.            |
| defaultVisibleDate  | `Date`                                                                                                     | -                                                                                       | The date used to decide which month should be initially displayed in the Day Grid.&#xA;To render a controlled Calendar, use the `visibleDate` prop instead.                                                                    |
| visibleDate         | `Date`                                                                                                     | -                                                                                       | The date used to decide which month should be displayed in the Day Grid.&#xA;To render an uncontrolled Calendar, use the `defaultVisibleDate` prop instead.                                                                    |
| onVisibleDateChange | `((visibleDate: Date, eventDetails: CalendarVisibleDateChangeEventDetails) => void)`                       | -                                                                                       | Event handler called when the visible date changes.&#xA;Provides the new date as an argument.&#xA;Has the change reason in the `eventDetails`.                                                                                 |
| isDateUnavailable   | `((day: Date) => boolean)`                                                                                 | -                                                                                       | Mark specific dates as unavailable.&#xA;Those dates will not be selectable but they will still be focusable with the keyboard.                                                                                                 |
| maxDate             | `Date`                                                                                                     | -                                                                                       | Maximal selectable date.                                                                                                                                                                                                       |
| minDate             | `Date`                                                                                                     | -                                                                                       | Minimal selectable date.                                                                                                                                                                                                       |
| monthPageSize       | `number`                                                                                                   | `1`                                                                                     | The amount of months to move by when navigating.&#xA;This is mostly useful when displaying multiple day grids.                                                                                                                 |
| referenceDate       | `Date`                                                                                                     | `'The closest valid date using the validation props.'`                                  | The date used to generate the new value when both `value` and `defaultValue` are empty.&#xA;It can be used to: set a desired time on the selected date;set a desired default year or month;                                    |
| timezone            | `string`                                                                                                   | `'The timezone of the "value" or "defaultValue" prop if defined, "default" otherwise.'` | Choose which timezone to use for the value.&#xA;Example: "default", "system", "UTC", "America/New_York".&#xA;If you pass values from other timezones to some props, they will be converted to this timezone before being used. |
| disabled            | `boolean`                                                                                                  | `false`                                                                                 | Whether the component should ignore user interaction.                                                                                                                                                                          |
| readOnly            | `boolean`                                                                                                  | `false`                                                                                 | Whether the user should be unable to select a date in the calendar.                                                                                                                                                            |
| invalid             | `boolean`                                                                                                  | `false`                                                                                 | Whether the calendar is forcefully marked as invalid.&#xA;A calendar can be invalid when the selected date fails validation (that is, is outside of the allowed `minDate` and `maxDate` range).                                |
| children            | `React.ReactNode \| ((parameters: CalendarContext) => React.ReactNode)`                                    | -                                                                                       | The children of the component.&#xA;If a function is provided, it will be called with the public context as its parameter.                                                                                                      |
| className           | `string \| ((state: Calendar.Root.State) => string \| undefined)`                                          | -                                                                                       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                                                       |
| style               | `React.CSSProperties \| ((state: Calendar.Root.State) => React.CSSProperties \| undefined)`                | -                                                                                       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                                                    |
| render              | `ReactElement \| ((props: HTMLProps, state: Calendar.Root.State) => ReactElement)`                         | -                                                                                       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.                                  |

**Root Data Attributes:**

| Attribute                 | Type                             | Description                                                                   |
| :------------------------ | :------------------------------- | :---------------------------------------------------------------------------- |
| data-disabled             | -                                | Present when the calendar is disabled.                                        |
| data-readonly             | -                                | Present when the calendar is readonly.                                        |
| data-invalid              | -                                | Present when the current value is invalid (fails validation).                 |
| data-empty                | -                                | Present when the current value is empty.                                      |
| data-navigation-direction | `'previous' \| 'next' \| 'none'` | Indicates the direction of the navigation (based on the month navigating to). |

### Root.Props

Re-export of [Root](/react/components/calendar.md) props.

### Root.State

```typescript
type CalendarRootState = {
  /** Whether the current value is empty. */
  empty: boolean;
  /** Whether the current value is invalid. */
  invalid: boolean;
  /** Whether the calendar is disabled. */
  disabled: boolean;
  /** Whether the calendar is readonly. */
  readOnly?: boolean;
  /** The direction of the navigation (based on the month navigating to). */
  navigationDirection: CalendarNavigationDirection;
};
```

### Root.ChangeEventReason

```typescript
type CalendarRootChangeEventReason =
  | 'month-change'
  | 'value-prop-change'
  | 'day-press'
  | 'keyboard';
```

### Root.NavigationDirection

```typescript
type CalendarRootNavigationDirection = 'previous' | 'next' | 'none';
```

### Root.ValueChangeEventDetails

```typescript
type CalendarRootValueChangeEventDetails = (
  | { reason: 'month-change'; event: Event }
  | { reason: 'value-prop-change'; event: Event }
  | { reason: 'day-press'; event: Event }
  | { reason: 'keyboard'; event: KeyboardEvent }
) & {
  /** Cancels Base UI from handling the event. */
  cancel: () => void;
  /** Allows the event to propagate in cases where Base UI will stop the propagation. */
  allowPropagation: () => void;
  /** Indicates whether the event has been canceled. */
  isCanceled: boolean;
  /** Indicates whether the event is allowed to propagate. */
  isPropagationAllowed: boolean;
  /** The element that triggered the event, if applicable. */
  trigger: Element | undefined;
  /** The validation error associated to the new value. */
  getValidationError: () => ValidateDateReturnValue;
};
```

### Root.ValueChangeHandlerContext

```typescript
type CalendarRootValueChangeHandlerContext = {
  /** The validation error associated to the new value. */
  getValidationError: () => ValidateDateReturnValue;
};
```

### Root.VisibleDateChangeEventDetails

```typescript
type CalendarRootVisibleDateChangeEventDetails = (
  | { reason: 'month-change'; event: Event }
  | { reason: 'value-prop-change'; event: Event }
  | { reason: 'day-press'; event: Event }
  | { reason: 'keyboard'; event: KeyboardEvent }
) & {
  /** Cancels Base UI from handling the event. */
  cancel: () => void;
  /** Allows the event to propagate in cases where Base UI will stop the propagation. */
  allowPropagation: () => void;
  /** Indicates whether the event has been canceled. */
  isCanceled: boolean;
  /** Indicates whether the event is allowed to propagate. */
  isPropagationAllowed: boolean;
  /** The element that triggered the event, if applicable. */
  trigger: Element | undefined;
};
```

### Viewport

A viewport for displaying calendar month transitions.
This component is only required if you want to animate certain part of a calendar when navigating between months.
The first rendered child element has to handle a ref.
Passes `data-current` to the currently visible content and `data-previous` to the previous content when animating between two.
Doesn't render its own HTML element.

**Viewport Props:**

| Prop       | Type                | Default | Description                                            |
| :--------- | :------------------ | :------ | :----------------------------------------------------- |
| children\* | `React.JSX.Element` | -       | The content to render inside the transition container. |

**Viewport Data Attributes:**

| Attribute                 | Type                             | Description                                                                                                        |
| :------------------------ | :------------------------------- | :----------------------------------------------------------------------------------------------------------------- |
| data-current              | -                                | Applied to the direct child of the viewport when no transitions are present or the new content when it's entering. |
| data-navigation-direction | `'previous' \| 'next' \| 'none'` | Indicates the direction of the navigation (based on the month navigating to).                                      |
| data-previous             | -                                | Applied to the direct child of the viewport that contains the exiting content when transitions are present.        |
| data-starting-style       | -                                | Present when the day grid body is animating in.                                                                    |
| data-ending-style         | -                                | Present when the day grid body is animating out.                                                                   |

### Viewport.Props

Re-export of [Viewport](/react/components/calendar.md) props.

### Viewport.State

```typescript
type CalendarViewportState = {
  /** Indicates the direction of the navigation (based on the month navigating to). */
  navigationDirection: CalendarNavigationDirection;
};
```

### DayButton

An individual interactive day button in the calendar.
Renders a `<button>` element.

**DayButton Props:**

| Prop                  | Type                                                                                             | Default                      | Description                                                                                                                                                                                   |
| :-------------------- | :----------------------------------------------------------------------------------------------- | :--------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| focusableWhenDisabled | `boolean`                                                                                        | `false`                      | When `true` the item remains focusable when disabled.                                                                                                                                         |
| nativeButton          | `boolean`                                                                                        | `true`                       | Whether the component renders a native `<button>` element when replacing it&#xA;via the `render` prop.&#xA;Set to `false` if the rendered element is not a button (for example, `<div>`).     |
| format                | `string`                                                                                         | `adapter.formats.dayOfMonth` | The format used to display the day.                                                                                                                                                           |
| className             | `string \| ((state: Calendar.DayButton.State) => string \| undefined)`                           | -                            | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style                 | `React.CSSProperties \| ((state: Calendar.DayButton.State) => React.CSSProperties \| undefined)` | -                            | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render                | `ReactElement \| ((props: HTMLProps, state: Calendar.DayButton.State) => ReactElement)`          | -                            | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

**DayButton Data Attributes:**

| Attribute          | Type | Description                                                                     |
| :----------------- | :--- | :------------------------------------------------------------------------------ |
| data-selected      | -    | Present when the day is selected.                                               |
| data-disabled      | -    | Present when the day is disabled.                                               |
| data-current       | -    | Present when the day is the current date.                                       |
| data-outside-month | -    | Present when the day is outside the month rendered by the day grid wrapping it. |
| data-unavailable   | -    | Present when the day is unavailable.                                            |

### DayButton.Props

Re-export of [DayButton](/react/components/calendar.md) props.

### DayButton.State

```typescript
type CalendarDayButtonState = {
  /** Whether the day is selected. */
  selected: boolean;
  /** Whether the day is disabled. */
  disabled: boolean;
  /** Whether the day is not available. */
  unavailable: boolean;
  /** Whether the day contains the current date. */
  current: boolean;
  /** Whether the day is outside the month rendered by the day grid wrapping it. */
  outsideMonth: boolean;
};
```

### DayGrid

Groups all the parts of the calendar's day grid.
Renders a `<table>` element.

**DayGrid Props:**

| Prop      | Type                                                                                           | Default | Description                                                                                                                                                                                   |
| :-------- | :--------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| className | `string \| ((state: Calendar.DayGrid.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style     | `React.CSSProperties \| ((state: Calendar.DayGrid.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render    | `ReactElement \| ((props: HTMLProps, state: Calendar.DayGrid.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

### DayGrid.Props

Re-export of [DayGrid](/react/components/calendar.md) props.

### DayGrid.State

```typescript
type CalendarDayGridState = {};
```

### DayGridBody

Groups all parts of the calendar's day grid.
Renders a `<tbody>` element.

**DayGridBody Props:**

| Prop            | Type                                                                                               | Default | Description                                                                                                                                                                                   |
| :-------------- | :------------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| fixedWeekNumber | `number`                                                                                           | -       | Will render the requested amount of weeks by adding weeks of the next month if needed.&#xA;Set it to 6 to create a Gregorian calendar where all months have the same number of weeks.         |
| offset          | `number`                                                                                           | `0`     | The offset to apply to the rendered month compared to the current month.&#xA;This is mostly useful when displaying multiple day grids.                                                        |
| children        | `React.ReactNode \| ((week: Date, index: number, weeks: Date[]) => React.ReactNode)`               | -       | The children of the component.&#xA;If a function is provided, it will be called for each week to render as its parameter.                                                                     |
| className       | `string \| ((state: Calendar.DayGridBody.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style           | `React.CSSProperties \| ((state: Calendar.DayGridBody.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render          | `ReactElement \| ((props: HTMLProps, state: Calendar.DayGridBody.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

### DayGridBody.Props

Re-export of [DayGridBody](/react/components/calendar.md) props.

### DayGridBody.State

```typescript
type CalendarDayGridBodyState = {};
```

### DayGridCell

An individual day cell in the calendar.
Renders a `<td>` element.

**DayGridCell Props:**

| Prop      | Type                                                                                               | Default | Description                                                                                                                                                                                   |
| :-------- | :------------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| value\*   | `Date`                                                                                             | -       | The value to select when this cell is clicked.                                                                                                                                                |
| className | `string \| ((state: Calendar.DayGridCell.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style     | `React.CSSProperties \| ((state: Calendar.DayGridCell.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render    | `ReactElement \| ((props: HTMLProps, state: Calendar.DayGridCell.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

### DayGridCell.Props

Re-export of [DayGridCell](/react/components/calendar.md) props.

### DayGridCell.State

```typescript
type CalendarDayGridCellState = {};
```

### DayGridHeader

Groups all parts of the calendar's day grid header.
Renders a `<thead>` element.

**DayGridHeader Props:**

| Prop      | Type                                                                                                 | Default | Description                                                                                                                                                                                   |
| :-------- | :--------------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| className | `string \| ((state: Calendar.DayGridHeader.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style     | `React.CSSProperties \| ((state: Calendar.DayGridHeader.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render    | `ReactElement \| ((props: HTMLProps, state: Calendar.DayGridHeader.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

### DayGridHeader.Props

Re-export of [DayGridHeader](/react/components/calendar.md) props.

### DayGridHeader.State

```typescript
type CalendarDayGridHeaderState = {};
```

### DayGridHeaderCell

An individual day header cell in the calendar.
Renders a `<th>` element.

**DayGridHeaderCell Props:**

| Prop      | Type                                                                                                     | Default                                                         | Description                                                                                                                                                                                   |
| :-------- | :------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| value\*   | `Date`                                                                                                   | -                                                               | -                                                                                                                                                                                             |
| formatter | `((date: Date) => string)`                                                                               | `(date) => adapter.format(date, 'EEE').charAt(0).toUpperCase()` | The formatter function used to display the day of the week.                                                                                                                                   |
| className | `string \| ((state: Calendar.DayGridHeaderCell.State) => string \| undefined)`                           | -                                                               | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style     | `React.CSSProperties \| ((state: Calendar.DayGridHeaderCell.State) => React.CSSProperties \| undefined)` | -                                                               | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render    | `ReactElement \| ((props: HTMLProps, state: Calendar.DayGridHeaderCell.State) => ReactElement)`          | -                                                               | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

### DayGridHeaderCell.Props

Re-export of [DayGridHeaderCell](/react/components/calendar.md) props.

### DayGridHeaderCell.State

```typescript
type CalendarDayGridHeaderCellState = {};
```

### DayGridHeaderRow

Groups all cells of the calendar's day grid header row.
Renders a `<tr>` element.

**DayGridHeaderRow Props:**

| Prop      | Type                                                                                                    | Default | Description                                                                                                                                                                                   |
| :-------- | :------------------------------------------------------------------------------------------------------ | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| children  | `React.ReactNode \| ((day: Date, index: number, days: Date[]) => React.ReactNode)`                      | -       | The children of the component.&#xA;If a function is provided, it will be called for each day of the week as its parameter.                                                                    |
| className | `string \| ((state: Calendar.DayGridHeaderRow.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style     | `React.CSSProperties \| ((state: Calendar.DayGridHeaderRow.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render    | `ReactElement \| ((props: HTMLProps, state: Calendar.DayGridHeaderRow.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

### DayGridHeaderRow\.Props

Re-export of [DayGridHeaderRow](/react/components/calendar.md) props.

### DayGridHeaderRow\.State

```typescript
type CalendarDayGridHeaderRowState = {};
```

### DayGridRow

Groups all cells of a given calendar's day grid row.
Renders a `<tr>` element.

**DayGridRow Props:**

| Prop      | Type                                                                                              | Default | Description                                                                                                                                                                                   |
| :-------- | :------------------------------------------------------------------------------------------------ | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| value\*   | `Date`                                                                                            | -       | The date object representing the week.                                                                                                                                                        |
| children  | `React.ReactNode \| ((day: Date, index: number, days: Date[]) => React.ReactNode)`                | -       | The children of the component.&#xA;If a function is provided, it will be called for each day of the week as its parameter.                                                                    |
| className | `string \| ((state: Calendar.DayGridRow.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style     | `React.CSSProperties \| ((state: Calendar.DayGridRow.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render    | `ReactElement \| ((props: HTMLProps, state: Calendar.DayGridRow.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

### DayGridRow\.Props

Re-export of [DayGridRow](/react/components/calendar.md) props.

### DayGridRow\.State

```typescript
type CalendarDayGridRowState = {};
```

### DecrementMonth

Displays an element to navigate to the previous month in the calendar.
Renders a `<button>` element.

**DecrementMonth Props:**

| Prop         | Type                                                                                                  | Default | Description                                                                                                                                                                                   |
| :----------- | :---------------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| nativeButton | `boolean`                                                                                             | `true`  | Whether the component renders a native `<button>` element when replacing it&#xA;via the `render` prop.&#xA;Set to `false` if the rendered element is not a button (for example, `<div>`).     |
| className    | `string \| ((state: Calendar.DecrementMonth.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style        | `React.CSSProperties \| ((state: Calendar.DecrementMonth.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render       | `ReactElement \| ((props: HTMLProps, state: Calendar.DecrementMonth.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

**DecrementMonth Data Attributes:**

| Attribute     | Type | Description                          |
| :------------ | :--- | :----------------------------------- |
| data-disabled | -    | Present when the button is disabled. |

### DecrementMonth.Props

Re-export of [DecrementMonth](/react/components/calendar.md) props.

### DecrementMonth.State

```typescript
type CalendarDecrementMonthState = {
  /** Whether the button is disabled. */
  disabled: boolean;
};
```

### IncrementMonth

Displays an element to navigate to the next month in the calendar.
Renders a `<button>` element.

**IncrementMonth Props:**

| Prop         | Type                                                                                                  | Default | Description                                                                                                                                                                                   |
| :----------- | :---------------------------------------------------------------------------------------------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| nativeButton | `boolean`                                                                                             | `true`  | Whether the component renders a native `<button>` element when replacing it&#xA;via the `render` prop.&#xA;Set to `false` if the rendered element is not a button (for example, `<div>`).     |
| className    | `string \| ((state: Calendar.IncrementMonth.State) => string \| undefined)`                           | -       | CSS class applied to the element, or a function that&#xA;returns a class based on the component's state.                                                                                      |
| style        | `React.CSSProperties \| ((state: Calendar.IncrementMonth.State) => React.CSSProperties \| undefined)` | -       | Style applied to the element, or a function that&#xA;returns a style object based on the component's state.                                                                                   |
| render       | `ReactElement \| ((props: HTMLProps, state: Calendar.IncrementMonth.State) => ReactElement)`          | -       | Allows you to replace the component's HTML element&#xA;with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

**IncrementMonth Data Attributes:**

| Attribute     | Type | Description                          |
| :------------ | :--- | :----------------------------------- |
| data-disabled | -    | Present when the button is disabled. |

### IncrementMonth.Props

Re-export of [IncrementMonth](/react/components/calendar.md) props.

### IncrementMonth.State

```typescript
type CalendarIncrementMonthState = {
  /** Whether the button is disabled. */
  disabled: boolean;
};
```

### useContext

**Return Value:**

```tsx
type ReturnValue = CalendarContext;
```

### useDayList

**Return Value:**

```tsx
type ReturnValue = UseCalendarDayListReturnValue;
```

### useWeekList

**Return Value:**

```tsx
type ReturnValue = UseWeekListReturnValue;
```

## Additional Types

### CalendarContext

```typescript
type CalendarContext = {
  visibleDate: Date;
  setVisibleDate: (
    visibleDate: Date,
    nativeEvent?: Event,
    trigger?: HTMLElement,
    reason?: CalendarChangeEventReason,
  ) => void;
};
```

## External Types

### UseWeekListReturnValue

```typescript
type UseWeekListReturnValue = (parameters: {
  date: Date;
  amount: number | 'end-of-month';
}) => unknown;
```

### UseCalendarDayListReturnValue

```typescript
type UseCalendarDayListReturnValue = (parameters: { date: Date; amount: number }) => unknown;
```

## Export Groups

- `Calendar.Root`: `Calendar.Root`, `Calendar.Root.NavigationDirection`, `Calendar.Root.State`, `Calendar.Root.Props`, `Calendar.Root.ValueChangeHandlerContext`, `Calendar.Root.ChangeEventReason`, `Calendar.Root.ValueChangeEventDetails`, `Calendar.Root.VisibleDateChangeEventDetails`
- `Calendar.DayGrid`: `Calendar.DayGrid`, `Calendar.DayGrid.State`, `Calendar.DayGrid.Props`
- `Calendar.DayGridHeader`: `Calendar.DayGridHeader`, `Calendar.DayGridHeader.State`, `Calendar.DayGridHeader.Props`
- `Calendar.DayGridHeaderRow`: `Calendar.DayGridHeaderRow`, `Calendar.DayGridHeaderRow.State`, `Calendar.DayGridHeaderRow.Props`
- `Calendar.DayGridHeaderCell`: `Calendar.DayGridHeaderCell`, `Calendar.DayGridHeaderCell.State`, `Calendar.DayGridHeaderCell.Props`
- `Calendar.DayGridBody`: `Calendar.DayGridBody`, `Calendar.DayGridBody.State`, `Calendar.DayGridBody.Props`
- `Calendar.DayGridRow`: `Calendar.DayGridRow`, `Calendar.DayGridRow.State`, `Calendar.DayGridRow.Props`
- `Calendar.DayGridCell`: `Calendar.DayGridCell`, `Calendar.DayGridCell.State`, `Calendar.DayGridCell.Props`
- `Calendar.DayButton`: `Calendar.DayButton`, `Calendar.DayButton.State`, `Calendar.DayButton.Props`
- `Calendar.DecrementMonth`: `Calendar.DecrementMonth`, `Calendar.DecrementMonth.State`, `Calendar.DecrementMonth.Props`
- `Calendar.IncrementMonth`: `Calendar.IncrementMonth`, `Calendar.IncrementMonth.State`, `Calendar.IncrementMonth.Props`
- `Calendar.useContext`
- `Calendar.useWeekList`
- `Calendar.useDayList`
- `Calendar.Viewport`: `Calendar.Viewport`, `Calendar.Viewport.Props`, `Calendar.Viewport.State`
- `Default`: `CalendarRootNavigationDirection`, `CalendarRootState`, `CalendarRootProps`, `CalendarRootValueChangeHandlerContext`, `CalendarRootChangeEventReason`, `CalendarRootValueChangeEventDetails`, `CalendarRootVisibleDateChangeEventDetails`, `CalendarDayGridState`, `CalendarDayGridProps`, `CalendarDayGridBodyState`, `CalendarDayGridBodyProps`, `CalendarDayGridCellState`, `CalendarDayGridCellProps`, `CalendarDayGridHeaderState`, `CalendarDayGridHeaderProps`, `CalendarDayGridHeaderCellState`, `CalendarDayGridHeaderCellProps`, `CalendarDayGridHeaderRowState`, `CalendarDayGridHeaderRowProps`, `CalendarDayGridRowState`, `CalendarDayGridRowProps`, `CalendarDayButtonState`, `CalendarDayButtonProps`, `CalendarIncrementMonthState`, `CalendarIncrementMonthProps`, `CalendarDecrementMonthState`, `CalendarDecrementMonthProps`, `CalendarViewportProps`, `CalendarViewportState`, `CalendarContext`

## Canonical Types

Maps `Canonical`: `Alias` — Use Canonical when its namespace is already imported; otherwise use Alias.

- `Calendar.Root.NavigationDirection`: `CalendarRootNavigationDirection`
- `Calendar.Root.State`: `CalendarRootState`
- `Calendar.Root.Props`: `CalendarRootProps`
- `Calendar.Root.ValueChangeHandlerContext`: `CalendarRootValueChangeHandlerContext`
- `Calendar.Root.ChangeEventReason`: `CalendarRootChangeEventReason`
- `Calendar.Root.ValueChangeEventDetails`: `CalendarRootValueChangeEventDetails`
- `Calendar.Root.VisibleDateChangeEventDetails`: `CalendarRootVisibleDateChangeEventDetails`
- `Calendar.DayGrid.State`: `CalendarDayGridState`
- `Calendar.DayGrid.Props`: `CalendarDayGridProps`
- `Calendar.DayGridHeader.State`: `CalendarDayGridHeaderState`
- `Calendar.DayGridHeader.Props`: `CalendarDayGridHeaderProps`
- `Calendar.DayGridHeaderRow.State`: `CalendarDayGridHeaderRowState`
- `Calendar.DayGridHeaderRow.Props`: `CalendarDayGridHeaderRowProps`
- `Calendar.DayGridHeaderCell.State`: `CalendarDayGridHeaderCellState`
- `Calendar.DayGridHeaderCell.Props`: `CalendarDayGridHeaderCellProps`
- `Calendar.DayGridBody.State`: `CalendarDayGridBodyState`
- `Calendar.DayGridBody.Props`: `CalendarDayGridBodyProps`
- `Calendar.DayGridRow.State`: `CalendarDayGridRowState`
- `Calendar.DayGridRow.Props`: `CalendarDayGridRowProps`
- `Calendar.DayGridCell.State`: `CalendarDayGridCellState`
- `Calendar.DayGridCell.Props`: `CalendarDayGridCellProps`
- `Calendar.DayButton.State`: `CalendarDayButtonState`
- `Calendar.DayButton.Props`: `CalendarDayButtonProps`
- `Calendar.DecrementMonth.State`: `CalendarDecrementMonthState`
- `Calendar.DecrementMonth.Props`: `CalendarDecrementMonthProps`
- `Calendar.IncrementMonth.State`: `CalendarIncrementMonthState`
- `Calendar.IncrementMonth.Props`: `CalendarIncrementMonthProps`
- `Calendar.Viewport.Props`: `CalendarViewportProps`
- `Calendar.Viewport.State`: `CalendarViewportState`
