Tommy's inclusive datepicker

Github repository โ€ข NPM package

A human-friendly and fully accessible datepicker with support for natural language text input. Now as a standard Web Component written in Typescript!

Try typing "tomorrow", "in 10 days" or "May fifth to May tenth"!

Calendar is forked from the excellent sqrrl/wc-datepicker

Features

Demo

Current theme: light.css

Property Value
value
range
Enable range input
id*
A page-unique ID used to identify the component. Mandatory for accessibility!
label
Label used for the text input field
placeholder
Placeholder used for the text input field
locale
BCP 47 language tag
min-date
Earliest accepted date
max-date
Latest accepted date
disabled
Disable the datepicker
input-should-format
Format valid dates into a more readable date string
first-day-of-week
Configure the first week day
show-month-stepper
Enable month stepper
show-year-stepper
Enable year stepper
show-clear-button
Enable clear button
show-keyboard-hint
Displays a hint with available keyboard commands
show-today-button
Enable today button
start-date
Date to show initially
inline
Keep the calendar visible; turn off hiding

Limitations

Install

npm install --save inclusive-dates
# or
yarn add inclusive-dates

Usage

Via script tags

Include the following script tags in your HTML.

<head>
  <script
    type="module"
    src="https://cdn.jsdelivr.net/npm/inclusive-dates/dist/esm/inclusive-dates.js"
  />

  <!-- Loading the theme is optional. -->
  <link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/inclusive-dates/dist/themes/light.css"
  />
</head>

<body>
  <inclusive-dates></inclusive-dates>
</body>

Using a bundler

Import the component using a bundler like rollup.js or esbuild.

import { InclusiveDates } from "inclusive-dates/dist/components/inclusive-dates";

// Importing a theme is optional.
import "inclusive-dates/dist/themes/light.css";

customElements.define("inclusive-dates", InclusiveDates);

With a bundler and automatic lazy loading

If you are using a bundler and want to take advantage of automatic lazy loading, you can call the provided defineCustomElements function. This will only load a small entry file on page load. The component code is loaded only when the component is actually rendered.

import { defineCustomElements } from "inclusive-dates/dist/loader";

// Importing a theme is optional.
import "inclusive-dates/dist/themes/light.css";

defineCustomElements();

Options

Options with a primitive type can be passed as attributes. Non-primitive options have to be set as properties on the datepicker instance.

Example:
<inclusive-dates first-day-of-week="1" id="datepicker"></inclusive-dates>

<script>
  const datepicker = document.getElementById('datepicker');

  datepicker.disableDate = function(date) {
    // disable Sundays
    return date.getDay() === 0;
  }
</script>
Attribute / Property Type Default Description
disabled boolean false Disable the datepicker.
disableDate (date: Date) => boolean () => false Function that gets passed each displayed date. Should return true to disable it.
element-class-name string inclusive-dates Prefix for all element class names.
first-day-of-week number 0 Set first day of a week. 0 for Sunday, 6 for Saturday.
range boolean false Enable/disable range selection.
labels WCDatepickerLabels See below. Set label text.
locale string navigator?.language || 'en-US' BCP 47 locale string used to format dates.
show-clear-button boolean false Enable/disable the clear button.
show-month-stepper boolean true Enable/disable the month stepper buttons.
show-today-button boolean false Enable/disable the today button.
show-year-stepper boolean false Enable/disable the year stepper buttons.
start-date string The current date. Date in YYYY-MM-DD format used to determine the initially displayed month.
value Date | Date[] | undefined The currently selected date. Array of start and end date if range selection is enabled.
inline boolean false If true, the calendar will always be visible.
Default labels:
{
  clearButton: 'Clear value',
  monthSelect: 'Select month',
  nextMonthButton: 'Next month',
  nextYearButton: 'Next year',
  picker: 'Choose date',
  previousMonthButton: 'Previous month',
  previousYearButton: 'Previous year',
  todayButton: 'Show today',
  yearSelect: 'Select year'
}

Events

Name Type Description
selectDate CustomEvent<string | string[] | undefined> Fired when a date is selected.
changeMonth CustomEvent<{ month: number; year: number; }> Fired when the displayed month or year changes.
componentReady CustomEvent<void> Fired when this component is fully loaded at the first render.
Example:
<inclusive-dates id="datepicker"></inclusive-dates>

<script>
  const datepicker = document.getElementById('datepicker');

  datepicker.addEventListener('selectDate', function(event) {
    console.log(event.detail);
  });

  datepicker.addEventListener('componentReady', function(event) {
    console.log(datepicker.startDate);
  });
  </script>

Styling

Work in progress!

Browser support

Browser Supported versions
Google Chrome 61+
Apple Safari 11+
Mozilla Firefox 63+
Microsoft Edge 79+

Keyboard controls

Key Action
Tab Cycle through the focusable elements.
Space, Enter Select current day.
Arrow left Move cursor to previous day.
Arrow right Move cursor to next day.
Arrow up Move cursor to previous week.
Arrow down Move cursor to next week.
Page up Move cursor to previous month.
Page down Move cursor to next month.
Shift + Page up Move cursor to previous year.
Shift + Page down Move cursor to next year.
Home Move cursor to first day of the month.
End Move cursor to last day of the month.

License

Licensed under the MIT license.

About me

I'm Tommy Feldt, an accessibility specialist at Useit based in Stockholm, Sweden

I do inclusive UX design, frontend development, accessibility consulting, WCAG 2.1 audits, talks and more

Check out some of my work on GitHub or send me an e-mail