DATE PICKER: Calendar overlay for a single date or a range
MODES: Single | Range (with presets) | Bounded (min/max)

The product does not use input[type="date"] — the native control renders and behaves differently in every browser, and its calendar can't be styled. This is the widget the product actually uses. Requires date_picker_controller.js.

Single Date

Default mode. The field shows a readable date and keeps the machine-readable yyyy-mm-dd in data-value. Today carries a ring rather than a fill, so it stays visible when another day is selected. Escape closes and returns focus to the field.

<div data-controller="date-picker">…<div class="tw-date-picker">field + .tw-date-picker-panel</div></div>

Date Range (With Presets)

Range mode: data-date-picker-mode-value="range". The first click starts the range, the second closes it, and clicking before the start restarts rather than producing a backwards range. Presets are why most range pickers exist — “Last 7 days” is one click instead of two calendar hunts.

data-date-picker-mode-value="range" + .tw-date-picker-presets with data-days or data-start/data-end

Bounded Range (Min / Max)

Out-of-bounds days are disabled, not hidden — a family looking for a closed date needs to see that it exists and is unavailable, not wonder whether the calendar is broken. Set with data-date-picker-min-value / -max-value.

Open days run from 10 to 28 August.

data-date-picker-min-value="2026-08-10" data-date-picker-max-value="2026-08-28"