On this page Datepicker Datepicker

import "@m3e/web/datepicker";
Usage

This section outlines usage examples and configuration guidance for the components in this package.

Date string handling

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-datepicker uses a consistent, standards-aligned parsing model instead of relying on the browser's built-in Date.parse() rules.

When m3e-datepicker receives a date string, it automatically detects whether the value matches one of the ISO-8601 formats that can be parsed safely and unambiguously:

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.

Basic usage

Use the m3e-datepicker-toggle to open a m3e-datepicker. This component should be nested inside a clickable element and be associated with a picker by setting the for attribute to the id of the picker to open.

MM/DD/YYYY
<m3e-form-field variant="outlined">
  <label slot="label" for="field">Date Field</label>
  <input autocomplete="off" id="field" />
  <m3e-icon-button slot="suffix">
    <m3e-icon name="calendar_today"></m3e-icon>
    <m3e-datepicker-toggle for="datepicker"></m3e-datepicker-toggle>
  </m3e-icon-button>
  <span slot="hint">MM/DD/YYYY</span>
</m3e-form-field>
<m3e-datepicker id="datepicker"></m3e-datepicker>
Variants

The m3e-datepicker supports three appearance variants: docked (default), modal, and auto. Use the variant attribute to control how the picker is presented. When set to auto, the picker automatically selects the appropriate appearance based on the current screen size.

When using the modal variant, the value of the label attribute is used as the header text for the modal dialog.

All examples in this page use variant="auto".

<m3e-datepicker variant="auto"></m3e-datepicker>
Date selection

Use the date attribute to set the currently selected date, and listen for the change event to react when the user selects a new one. You can also enable the clearable attribute to display a button that clears the current selection.

MM/DD/YYYY
<!-- Form field omitted for brevity -->
<m3e-datepicker id="datepicker" date="2026-01-01" clearable></m3e-datepicker>
const picker = document.querySelector("#datepicker");
const field = document.querySelector("#field");
field.value = toLocaleDateString(picker.date);
picker.addEventListener("change", () => {
  field.value = toLocaleDateString(picker.date);
});
Start date

By default, a datepicker 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-datepicker should initially display.

MM/DD/YYYY
<!-- Form field omitted for brevity -->
<m3e-datepicker id="datepicker" start-at="2026-01-01"></m3e-datepicker>
Start view

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.

MM/DD/YYYY
<!-- Form field omitted for brevity -->
<m3e-datepicker id="datepicker" start-view="multi-year"></m3e-datepicker>
Date ranges

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.

MM/DD/YYYY - MM/DD/YYYY
<m3e-form-field variant="outlined">
  <label slot="label" for="field">Date Range Field</label>
  <input autocomplete="off" id="field" />
  <m3e-icon-button slot="suffix">
    <m3e-icon name="calendar_today"></m3e-icon>
    <m3e-datepicker-toggle for="range-picker"></m3e-datepicker-toggle>
  </m3e-icon-button>
  <span slot="hint">MM/DD/YYYY - MM/DD/YYYY</span>
</m3e-form-field>

<m3e-datepicker
  id="range-picker"
  range-start="2026-01-01"
  range-end="2026-01-09"
  start-at="2026-01-01"
></m3e-datepicker>
const picker = document.querySelector("#range-picker");
const field = document.querySelector("#field");
field.value = toLocaleDateString(picker.rangeStart) + " - " + toLocaleDateString(picker.rangeEnd);
picker.addEventListener("change", () => {
  field.value = toLocaleDateString(picker.rangeStart) + " - " + toLocaleDateString(picker.rangeEnd);
});
Min and max dates

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.

MM/DD/YYYY
<!-- Form field omitted for brevity -->
<m3e-datepicker
  id="picker1"
  start-at="2026-04-01"
  min-date="2026-01-01"
  max-date="2026-04-30"
></m3e-datepicker>
Blackout dates

Use the blackoutDates property to specify a function used to determine whether a date is disabled and cannot be selected by the user.

MM/DD/YYYY
document.querySelector("#blackout-dates").blackoutDates = (date) => isWeekend(date);
Special dates

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.

MM/DD/YYYY
document.querySelector("#special-dates").specialDates = (date) => isHoliday(date);
Internationalization

m3e-datepicker uses the Gregorian calendar, and all date formatting is handled by the browser's Intl APIs based on the active locale.

Accessibility

Datepickers are given ARIA role="dialog" to identify the picker surface as a discrete interactive region that opens above the page and requires user attention. When the picker is shown in its modal variant, it also sets aria-modal="true" to indicate that the rest of the page is inert and that focus is trapped within the dialog until it is dismissed. In docked mode, the picker omits aria-modal entirely, since the surrounding page remains interactive and the surface behaves like an anchored popover rather than a blocking dialog.

Datepicker toggles add aria-haspopup="dialog" to its parenting element indicating to assistive technologies that activating the control will open a dialog.

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.

Native module support

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/datepicker.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/calendar": "/node_modules/@m3e/web/dist/calendar.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.

API

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.