The m3e-calendar component provides structured navigation and selection across month, year, and
multi-year views. It supports single-date and range selection, applies disabled rules including minimum,
maximum, and blackout constraints, and provides styling hooks for special date states.
import "@m3e/web/calendar";
This section outlines usage examples and configuration guidance for the components in this package.
Different browsers interpret date strings in inconsistent ways, especially when the string resembles an ISO date
but does not include a time or timezone. To ensure predictable behavior across environments,
m3e-calendar uses a consistent, standards-aligned parsing model instead of relying on the browser's
built-in Date.parse() rules.
When m3e-calendar receives a date string, it automatically detects whether the value matches one of
the ISO-8601 formats that can be parsed safely and unambiguously:
yyyy-MM-dd — local date (no time, no timezone)yyyy-MM-ddTHH:mm:ss — local date and timeyyyy-MM-ddTHH:mm:ssZ — UTC date and timeyyyy-MM-ddTHH:mm:ss±HH:mm — date and time with an explicit timezone offset
Strings in these formats are converted into local Date objects without unexpected timezone shifts.
This prevents issues such as date-only values drifting into the previous or next day when interpreted as UTC. If
a string does not follow one of these ISO-compatible patterns, parsing may be ambiguous or unsupported. For the
most reliable results, use one of the formats above.
Set the date attribute to define the currently selected date. Listen for the
change event to respond when the user selects a new one.
<m3e-calendar id="calendar" date="2026-01-01"></m3e-calendar> <div id="selected-date"></div>
const calendar = document.querySelector("#calendar");
const selectedDate = document.querySelector("#selected-date");
selectedDate.textContent = "Selected Date:" + toLocaleDateString(calendar.date);
calendar.addEventListener("change", () => {
selectedDate.textContent = "Selected Date:" + toLocaleDateString(calendar.date);
});
By default, a calendar opens to the selected date, or to today if no date is set. You can override this by using
the start-at attribute to specify the date that m3e-calendar should initially display.
<m3e-calendar start-at="2026-01-01"></m3e-calendar>
The start-view attribute can be used to set the view that will show up when the calendar first
opens. It can be set to month, year, or multi-year; by default it will
open to month view.
<m3e-calendar start-view="multi-year"></m3e-calendar>
To select a range of dates instead of a single date, use the
range-start and range-end attributes. Setting range-start puts the
calendar into range-selection mode. When the user selects a date after the current range-start,
both date and range-end are updated to that value. If the user selects a date before
the current range-start, the range is reset and both date and
range-start are set to the newly selected date.
<m3e-calendar range-start="2026-01-01" range-end="2026-01-09" start-at="2026-01-01"></m3e-calendar>
Use the min-date and max-date to disable all dates on the calendar before or after the
respective values and prevent the user from advancing the calendar past the month or year (depending on current
view) containing the minimum or maximum date.
<m3e-calendar start-at="2026-04-01" min-date="2026-01-01" max-date="2026-04-30"></m3e-calendar>
Use the blackoutDates property to specify a function used to determine whether a date is disabled
and cannot be selected by the user.
<m3e-calendar id="blackout-dates"></m3e-calendar>
document.querySelector("#blackout-dates").blackoutDates = (date) => isWeekend(date);
Use the specialDates property to specify a function used to determine whether a date has a
highlighted look and feel. You can use the --m3e-calendar-item-special-container-color,
--m3e-calendar-item-special-color, --m3e-calendar-item-special-ripple-color,
--m3e-calendar-item-special-hover-color, and
--m3e-calendar-item-special-focus-color CSS properties to style special dates.
<m3e-calendar id="special-dates" start-at="2026-04-01"></m3e-calendar>
document.querySelector("#special-dates").specialDates = (date) => isHoliday(date);
m3e-calendar uses the Gregorian calendar, and all date formatting is handled by the browser's
Intl APIs based on the active locale.
The calendar is fully accessible and exposes clear semantics for assistive technologies. The header contains
navigation controls, each with an accessible label that can be customized through attributes. The calendar grid
is implemented using role="grid", with each date cell using role="gridcell" and
containing a focusable element with role="button". Selected dates and range boundaries are
indicated using aria-pressed, while today's date is marked with aria-current="date".
Each cell includes a visually hidden, locale-aware full date string for screen readers, while the visible text
shows only the day number. Day-of-week headers use abbreviated labels but include visually hidden full names
(such as “Monday”) to ensure clear, unambiguous announcements.
previous-month-label — Accessible label for the button that navigates to the previous month.
next-month-label — Accessible label for the button that navigates to the next month.previous-year-label — Accessible label for the button that navigates to the previous year.next-year-label — Accessible label for the button that navigates to the next year.previous-multi-year-label — Accessible label for the button that navigates to the previous
24-year range.
next-multi-year-label — Accessible label for the button that navigates to the next 24-year range.
The @m3e/web package uses
JavaScript Modules. To use it directly in a browser without a bundler, use a module script similar to the following.
<script type="module" src="/node_modules/@m3e/web/dist/calendar.js"></script>
In addition, you must use an import map to include dependencies.
<script type="importmap">
{
"imports": {
"tslib": "https://cdn.jsdelivr.net/npm/tslib@2.8.1/+esm",
"lit": "https://cdn.jsdelivr.net/npm/lit@3.3.0/+esm",
"lit/": "https://cdn.jsdelivr.net/npm/lit@3.3.0/",
"lit-html": "https://cdn.jsdelivr.net/npm/lit-html@3.3.0/+esm",
"lit-html/directive.js": "https://cdn.jsdelivr.net/npm/lit-html@3.3.0/directive.js",
"lit-html/directives/if-defined.js": "https://cdn.jsdelivr.net/npm/lit-html@3.3.0/directives/if-defined.js",
"lit-html/directives/class-map.js": "https://cdn.jsdelivr.net/npm/lit-html@3.3.0/directives/class-map.js",
"@lit/reactive-element": "https://cdn.jsdelivr.net/npm/@lit/reactive-element@2.0.4/+esm",
"@lit/reactive-element/": "https://cdn.jsdelivr.net/npm/@lit/reactive-element@2.0.4/",
"@m3e/web/core": "/node_modules/@m3e/web/dist/core.js",
"@m3e/web/core/a11y": "/node_modules/@m3e/web/dist/core-a11y.js"
"@m3e/web/core/anchoring": "/node_modules/@m3e/web/dist/core-anchoring.js",
"@m3e/web/core/bidi": "/node_modules/@m3e/web/dist/core-bidi.js",
"@m3e/web/core/platform": "/node_modules/@m3e/web/dist/core-platform.js"
"@m3e/web/button": "/node_modules/@m3e/web/dist/button.js",
"@m3e/web/icon-button": "/node_modules/@m3e/web/dist/icon-button.js",
"@m3e/web/tooltip": "/node_modules/@m3e/web/dist/tooltip.js"
}
}
</script>
For production builds, use the minified files to ensure optimal load performance.
The @m3e/web package includes a
Custom Elements Manifest (custom-elements.json), which documents the properties,
attributes, slots, events and CSS custom properties of each component.
You can explore the API below, or integrate the manifest into your own tooling.