Calendar

A grid-backed calendar for single-date and range selection with keyboard navigation and selection modes.

Features

  • Multiple selection modes
  • Grid-backed structure
  • Controlled or uncontrolled
  • Extensible header
  • Rich date state
  • Keyboard navigation

Installation

npm install @ariaui/calendar

Examples

Each playground is a self-contained example: single date, range, manual grid composition, dual-range two-pane layout, and month/year Select controls in the header.

Styling uses semantic tokens (border-border, bg-card, text-foreground, etc.) and lucide-react icons. Snippets for the manual grid interpolate the same class strings as the live preview.

Single date

One selected day with header navigation and manual-grid styling.

Preview

No preview output yet.

live.tsxReady

Range

Start and end dates with in-range highlighting.

Preview

No preview output yet.

live.tsxReady

Manual grid

Compose Calendar.Row and Calendar.Cell with Grid.Head and Grid.Body for full control over the matrix.

Preview

No preview output yet.

live.tsxReady

Dual range

Two-month layout with a shared range selection model.

Preview

No preview output yet.

live.tsxReady

Month and year selectors

Replace static month and year labels with Select-driven controls wired to calendar context.

Preview

No preview output yet.

live.tsxReady

Anatomy

tsx
import * as Calendar from "@ariaui/calendar";

export default function Example() {
  return (
    <Calendar.Root>
      <Calendar.Header>
        <Calendar.HeaderPrevious />
        <Calendar.HeaderMonth />
        <Calendar.HeaderYear />
        <Calendar.MonthSelect />
        <Calendar.YearSelect />
        <Calendar.HeaderNext />
      </Calendar.Header>
      <Calendar.Body>
        <Calendar.Head>
          <Calendar.Row>
            <Calendar.DayHeader />
          </Calendar.Row>
        </Calendar.Head>
        <Calendar.Rows>
          <Calendar.Row>
            <Calendar.Cell />
          </Calendar.Row>
        </Calendar.Rows>
      </Calendar.Body>
    </Calendar.Root>
  );
}

API Reference

Root

Container that owns all calendar state — selected dates, visible month, and selection mode. Provides context to all child parts. Renders a `<div>`.

PropTypeDefault
daysInWeek*
Record<string, string>
mode
"single" | "range" | "dual-range""single"
defaultDates
Date[][]
selectedDates
Date[]
onValueChange
(dates: Date[]) => void
visibleMonth
Date
onVisibleMonthChange
(date: Date) => void
AttributeValues
[data-slot]"calendar-root"

Body

Renders the weekday header row and the grid-backed date cells for the visible month. In `dual-range` mode, renders both month panes automatically. Renders a `<div>`.

AttributeValues
[data-slot]"calendar-body"

Cell

Individual date cell. Wraps the shared Grid.Cell primitive and layers date-specific selection and range state on top. Renders a `<td>`.

PropTypeDefault
date*
Date
isOutsideMonth
booleanfalse
AttributeValues
[data-slot]"calendar-cell"
[data-selected]Present when the date is selected
[data-today]Present when the date is today
[data-range-start]Present when the date is the range start endpoint
[data-range-end]Present when the date is the range end endpoint
[data-in-range]Present when the date falls within the committed range

Keyboard

ShortcutAction
Move focus to the next day. Crossing a week or month boundary updates the visible month.
Move focus to the previous day. Crossing a week or month boundary updates the visible month.
Move focus to the same day of the next week.
Move focus to the same day of the previous week.
HomeMove focus to the first day of the current week.
EndMove focus to the last day of the current week.
Enter/SpaceSelect the focused date.
PageDownMove the calendar forward one month.
PageUpMove the calendar back one month.
Shift+PageDownMove the calendar forward one year.
Shift+PageUpMove the calendar back one year.

Grid cell focus automatically updates the visible month when navigating across boundaries, and day-number fallback is applied when jumping to a month that lacks the target day.

Accessibility

The Calendar component implements the WAI-ARIA Date Picker Dialog pattern. Date cells use a grid structure with proper ARIA attributes:

  • [aria-selected="true"] marks the selected date(s)
  • [aria-disabled="true"] marks dates outside the visible month
  • [data-today] identifies the current date for visual distinction
  • Range mode exposes [data-range-start], [data-range-end], and [data-in-range] for styling range spans

Each date cell is keyboard-focusable and selectable via Enter/Space. Month/year navigation is exposed in the header via buttons with accessible labels.

Previous
Button Group
Next
Card