Date picker

A text field with an empty panel

Focus or a click on the field opens the calendar. A date can also be typed as YYYY-MM-DD.

A page loads the calendar library itself, before the Tsunami script

The calendar is Vanilla Calendar Pro 3.4.0 (MIT licence). It is not in tsunami.min.js: a page that has a .date-picker loads dist/vanilla-calendar.min.js with its own <script> first. A page with no date picker does not load it and is not affected. With the script missing, each .date-picker logs an error and stays an empty field. The library's own stylesheet is not used: the calendar is drawn by tsunami.css.

<script src="https://cdn.jsdelivr.net/gh/Djirasak/tsunami-framework@v0.1.3/dist/vanilla-calendar.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/Djirasak/tsunami-framework@v0.1.3/dist/tsunami.min.js"></script>

The field's value attribute is the starting date

data-format="long" shows a written date, chosen from the calendar only

The field is read only: a written date such as May 29, 2026 cannot be typed.

data-mode="range" picks a start and an end date

Two clicks choose the range. Two months show side by side from 768px wide, one below that. A range is typed as start to end.

A button shows the date, or data-placeholder while none is chosen

The control can be a button holding a span. The span shows the chosen dates, a range with an arrow between its two ends, or the root's data-placeholder while there are none. The hidden input carries the starting value. A date cannot be typed.

Presets are ready-made dates beside the calendar

The page writes a data-presets group of buttons in the panel. A preset's value is the dates it chooses, written by the server, so the script works out no dates itself. Choosing one closes the panel, and the calendar stays for dates of one's own. From 768px wide the presets are a column after the calendar; below that they are two columns under it.

One control for a period: presets, or dates from the calendar. data-format="medium" writes the dates with a short month

The preset that matches the chosen dates has aria-pressed="true". The page writes it for the starting value; the script keeps it up to date.

data-min and data-max limit the dates that can be chosen

Days outside the limits are dimmed and cannot be chosen. A typed date outside them marks the field aria-invalid.

Between October 5 and November 15, 2026.

The input's data-size sets the height; the width is the root's

A hidden input carries the value for the form, always as YYYY-MM-DD

With data-format the text field shows a written date, so the form reads the hidden input, which is not shown.

Nothing sent yet.

Inside a dialog the calendar opens above the dialog, and Escape closes the calendar first

Change expiration date

Invalid, and disabled

A starting value that is not a date stays in the field as written, and the page's own aria-invalid and error text stay. The script clears aria-invalid once a valid date is typed or chosen.

Enter a date as YYYY-MM-DD.

The page reads the dates from the change event, and sets them through value

No dates yet.

Other library options go through mount()

Pass any option of Vanilla Calendar Pro when starting the date picker by hand. The options are laid over the ones the attributes set. mount() starts it again if it already has one.

tsunami.datePicker.mount(document.getElementById("delivery-date"), {
  firstWeekday: 0,
  disableWeekdays: [0, 6],
});

API

The members are on the .date-picker element itself; the functions live on window.tsunami.datePicker.

Member Type Description
value property Read: the chosen date, or start to end for a range, as YYYY-MM-DD; an empty string for none. Set: takes the same text; an empty string clears it, and so does text that is not a date.
open() method Opens the calendar.
close() method Closes it.
calendar property, read only The library's Calendar object, for anything its own API offers.
tsunami.datePicker.mount(el, options?) function Starts a date picker on a .date-picker element, with the library options laid over the attributes. Throws when Vanilla Calendar Pro is not loaded.
tsunami.datePicker.get(el) function The library's Calendar of that element, or null.
tsunami.datePicker.destroy(el) function Takes the calendar away and removes the members above.

Events

Event On Detail Description
change .date-picker { value, dates } Bubbles. Sent when the dates change, by a click, by a preset, by typing or by setting value. value is the text; dates is a list of one or two. The text field's own change is stopped, so a listener sees this one only. An input event also bubbles from the field that holds the value, so a form and a save bar notice the edit.

Keyboard

Key Description
Tab From the field or the button into the calendar, through its controls and then the presets, then out, which closes it.
Arrow keys Move between the days.
Enter, Space On a day, chooses it. On the button, opens or closes the calendar. On a preset, chooses its dates.
Escape Closes the calendar and returns to the field or the button. A dialog around it stays open.

Accessibility

The control gets aria-haspopup="dialog" and aria-controls; a button also gets aria-expanded. The panel is a dialog with an aria-label and is aria-hidden="true" until it opens. Give the text input a visible label (or an aria-label). For an error, set aria-invalid="true" on the input and point aria-describedby at the error text, which has role="alert". The days are buttons with a full date as their label, and the focus ring is the accent colour. Write role="group" and an aria-label on the presets.

Vanilla Calendar Pro 3.4.0 is MIT licensed (vendor/vanilla-calendar/LICENSE.txt). It is a separate file, dist/vanilla-calendar.min.js, not part of tsunami.min.js.

Attributes

Attribute / element Values Description
.date-picker The wrapper. It holds the control, an empty [data-popover] panel and, optionally, a hidden input.
data-mode range, on .date-picker A start and an end date, chosen with two clicks. Two months show side by side from 768px wide, one below that. Without it, one date.
data-format long, medium, on .date-picker The control shows a written date and takes none typed: May 29, 2026 for long, Sep 7, 2026 for medium. Without it the control shows YYYY-MM-DD, and a field takes it typed.
data-min YYYY-MM-DD, on .date-picker The first date that can be chosen.
data-max YYYY-MM-DD, on .date-picker The last date that can be chosen.
value YYYY-MM-DD or start to end, on the text input or the hidden input The starting date: 2026-05-29 for a date, 2026-05-01 to 2026-05-29 for a range. The hidden input's value wins when there is one. A date picker with a button starts from the hidden input.
data-placeholder text, on .date-picker With a button: the text the button shows while no date is chosen. With dates it shows them, a range as start → end.
data-empty present or absent, set by the script Present on .date-picker while there are no dates, so a button's text can be dimmed.
data-presets on a div in the panel Holds the presets: one button for each ready-made date or range, shown beside the calendar. Give it role="group" and an aria-label.
value YYYY-MM-DD or start to end, on a preset's button The dates the preset chooses, written as the starting value is.
aria-pressed true, false, on a preset's button true on the preset whose value is the chosen dates. The page writes it for the starting value; the script keeps it up to date.
data-size sm, lg, on the text input The height of the field: 28px, 36px (default) or 40px.
aria-invalid true, on the text input The field gets a red border, as an input does. The script sets it on a typed text that is not a date, or outside data-min and data-max.
data-date-picker-initialized true, set by the script On .date-picker once the calendar has started.