Calendar
Component

Calendar

A fully accessible, locale-aware calendar component with keyboard navigation following WAI-ARIA APG guidelines.

Demo

Selected: 2026-01-08

Features

  • Full keyboard navigation (Arrow keys, Home, End, Page Up/Down)
  • Locale-aware month/weekday names via browser's Intl API
  • Configurable week start day (Sunday, Monday, etc.)
  • Min/max date constraints
  • Fixed weeks option for consistent grid height
  • WCAG 2.1 AA compliant with proper ARIA attributes
  • Headless design - fully customizable styling
  • 13 calendar systems: Gregorian, Japanese, Buddhist, Persian, Hebrew, and more

Installation

bash
dotnet add package SummitUI

Anatomy

Import the components and structure them as follows:

razor
<CalendarRoot @bind-Value="selectedDate" Context="ctx">
    <CalendarHeader>
        <CalendarPrevButton />
        <CalendarHeading />
        <CalendarNextButton />
    </CalendarHeader>
    <CalendarGrid>
        <CalendarGridHead>
            <CalendarGridRow>
                @for (int i = 0; i < ctx.Weekdays.Length; i++)
                {
                    var idx = i;
                    <CalendarHeadCell Abbreviation="@ctx.WeekdaysLong[idx]">
                        @ctx.Weekdays[idx]
                    </CalendarHeadCell>
                }
            </CalendarGridRow>
        </CalendarGridHead>
        <CalendarGridBody>
            @foreach (var week in ctx.CurrentMonth.Weeks)
            {
                <CalendarGridRow>
                    @foreach (var date in week)
                    {
                        <CalendarCell Date="@date">
                            <CalendarDay />
                        </CalendarCell>
                    }
                </CalendarGridRow>
            }
        </CalendarGridBody>
    </CalendarGrid>
</CalendarRoot>

Sub-components

CalendarRoot

Root container managing calendar state and context.

CalendarHeader

Container for navigation controls and heading.

CalendarHeading

Displays the current month and year with live region.

CalendarPrevButton

Button to navigate to the previous month.

CalendarNextButton

Button to navigate to the next month.

CalendarGrid

The table element with role="grid" for the calendar.

CalendarGridHead

Table header containing weekday names.

CalendarGridBody

Table body containing date cells.

CalendarGridRow

A row in the calendar grid.

CalendarHeadCell

Weekday header cell with abbreviation support.

CalendarCell

A cell representing a single date.

CalendarDay

The interactive day button inside a cell.

API Reference

CalendarRoot

Property Type Default Description
Value DateOnly? null The currently selected date (two-way bindable)
ValueChanged EventCallback<DateOnly?> - Callback when the selected date changes
DefaultValue DateOnly? null Default value when uncontrolled
OnValueChange EventCallback<DateOnly?> - Alternative callback for value changes
Placeholder DateOnly? null Placeholder date for initial display when no value is set
Locale string? Browser locale Locale for formatting (e.g., "en-US", "de-DE")
WeekStartsOn WeekStartsOn? Locale default First day of the week (Sunday, Monday, etc.)
FixedWeeks bool false Always display 6 weeks for consistent height
MinValue DateOnly? null Minimum selectable date
MaxValue DateOnly? null Maximum selectable date
Disabled bool false Disables the entire calendar
ReadOnly bool false Allows navigation but prevents selection
IsDateDisabled Func<DateOnly, bool>? null Custom function to disable specific dates
CalendarSystem CalendarSystem Gregorian Calendar system to use for display (Japanese, Buddhist, Persian, etc.)

CalendarHeadCell

Property Type Default Description
Abbreviation string? null Full weekday name for screen readers (placed in abbr element)

CalendarCell

Property Type Default Description
Date required DateOnly - The date this cell represents

Examples

Basic Calendar

razor
@code {
    private DateOnly? selectedDate = DateOnly.FromDateTime(DateTime.Today);
}

<CalendarRoot @bind-Value="selectedDate" Context="ctx">
    <CalendarHeader class="flex items-center justify-between mb-4">
        <CalendarPrevButton class="..." />
        <CalendarHeading class="text-sm font-semibold" />
        <CalendarNextButton class="..." />
    </CalendarHeader>
    <CalendarGrid class="w-full">
        <!-- Grid content -->
    </CalendarGrid>
</CalendarRoot>

<p>Selected: @(selectedDate?.ToString("yyyy-MM-dd") ?? "None")</p>

Week Starts on Monday

Configure the first day of the week.

razor
<CalendarRoot @bind-Value="selectedDate" 
               WeekStartsOn="WeekStartsOn.Monday" 
               Context="ctx">
    <!-- Calendar content -->
</CalendarRoot>

Min/Max Date Constraints

Restrict selectable dates to a range.

razor
@code {
    private DateOnly? selectedDate;
    private DateOnly minDate = DateOnly.FromDateTime(DateTime.Today);
    private DateOnly maxDate = DateOnly.FromDateTime(DateTime.Today.AddDays(30));
}

<CalendarRoot @bind-Value="selectedDate" 
               MinValue="@minDate" 
               MaxValue="@maxDate"
               Context="ctx">
    <!-- Calendar content -->
</CalendarRoot>

Fixed Weeks

Always show 6 weeks for consistent height.

razor
<CalendarRoot @bind-Value="selectedDate" 
               FixedWeeks="true"
               Context="ctx">
    <!-- Always shows 6 weeks -->
</CalendarRoot>

Custom Date Disabled

Disable specific dates with a custom function.

razor
@code {
    private DateOnly? selectedDate;
    
    // Disable weekends
    private bool IsWeekend(DateOnly date) => 
        date.DayOfWeek == DayOfWeek.Saturday || 
        date.DayOfWeek == DayOfWeek.Sunday;
}

<CalendarRoot @bind-Value="selectedDate" 
               IsDateDisabled="IsWeekend"
               Context="ctx">
    <!-- Weekend dates are disabled -->
</CalendarRoot>

Calendar Systems

The calendar supports 13 different calendar systems. The selected date value is always stored as a Gregorian DateOnly, but displayed using the selected calendar system. This allows international users to interact with dates in their familiar format.

Selected (Gregorian): 2026-01-08

The standard Western calendar used worldwide.

Usage

razor
@code {
    private DateOnly? selectedDate;
    private CalendarSystem calendarSystem = CalendarSystem.Japanese;
}

<CalendarRoot @bind-Value="selectedDate" 
               CalendarSystem="calendarSystem"
               Locale="ja-JP"
               Context="ctx">
    <!-- Calendar content -->
    <!-- Heading will show Japanese era (e.g., 令和7年1月) -->
    <!-- Selected value remains Gregorian DateOnly -->
</CalendarRoot>

Supported Calendar Systems

System Region Description
Gregorian Worldwide Standard Western calendar
Japanese Japan Era-based (Reiwa, Heisei, Showa)
Buddhist Thailand, Cambodia, Laos Year = Gregorian + 543
Taiwan Taiwan ROC era, Year = Gregorian - 1911
Persian Iran, Afghanistan Solar calendar (Jalali)
Indian India Saka era, official civil calendar
IslamicUmalqura Saudi Arabia Lunar, astronomical calculations
IslamicCivil Islamic regions Lunar, tabular/arithmetic
IslamicTabular Islamic regions Lunar, algorithmic variant
Hebrew Israel Lunisolar, 12-13 months
Coptic Egypt Coptic Orthodox Church calendar
Ethiopic Ethiopia Official calendar of Ethiopia
EthiopicAmeteAlem Ethiopia Alternate era calculation

Styling

Data Attributes

Attribute Element Description
data-summit-calendar-root CalendarRoot Marks the root element
data-summit-calendar-grid CalendarGrid Marks the grid table
data-summit-calendar-day CalendarDay Marks day buttons
data-date CalendarDay ISO date string (YYYY-MM-DD)
data-state CalendarDay "selected" when date is selected
data-today CalendarDay Present when date is today
data-focused CalendarDay Present on keyboard-focused date
data-outside-month CalendarDay Present for dates outside current month
data-unavailable CalendarDay Present for dates outside min/max or custom disabled
data-disabled Multiple Present when calendar or element is disabled

Tailwind Example

css
/* Calendar day styling with Tailwind */
.calendar-day {
    @apply w-9 h-9 rounded-md text-sm
           hover:bg-accent
           focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2;
}

.calendar-day[data-today] {
    @apply font-semibold text-primary;
}

.calendar-day[data-state="selected"] {
    @apply bg-primary text-primary-foreground;
}

.calendar-day[data-outside-month] {
    @apply text-muted-foreground opacity-50;
}

.calendar-day[data-unavailable] {
    @apply text-muted-foreground opacity-50 cursor-not-allowed;
}

.calendar-day[data-focused] {
    @apply ring-2 ring-primary ring-offset-2;
}

Accessibility

Keyboard Navigation

Key Action
ArrowRight Move focus to next day
ArrowLeft Move focus to previous day
ArrowDown Move focus to same day next week
ArrowUp Move focus to same day previous week
Home Move focus to start of week
End Move focus to end of week
PageDown Move focus to next month
PageUp Move focus to previous month
Shift + PageDown Move focus to next year
Shift + PageUp Move focus to previous year
Enter / Space Select the focused date

ARIA Attributes

  • Grid: Has role="grid" with aria-labelledby pointing to heading
  • Heading: Uses aria-live="polite" and aria-atomic="true" to announce month changes
  • Days: Each has aria-selected, aria-disabled, and aria-current="date" for today
  • Navigation: Buttons have descriptive aria-label ("Previous month", "Next month")
  • Focus: Uses roving tabindex pattern - only focused date has tabindex="0"
An unhandled error has occurred. Reload X