Data inputExtension
Date Range Picker
A typed start and end date field with presets and a two-month calendar, backed by two native date inputs.
| Class name | Type | Description |
|---|---|---|
date-pickerplf:date-picker | Component | A Date Picker in range mode |
calendarplf:calendar | Component | The range calendar |
date-picker-inputsplf:date-picker-inputs | Part | The row of native start and end fields |
date-picker-fieldplf:date-picker-field | Part | A field that fills its row |
date-picker-controlsplf:date-picker-controls | Part | The hidden controls the script shows |
date-picker-panelplf:date-picker-panel | Part | The Popover panel |
date-picker-bodyplf:date-picker-body | Part | The presets and calendar |
date-picker-presetsplf:date-picker-presets | Part | The preset buttons |
date-picker-preset-fieldplf:date-picker-preset-field | Part | The preset select's field the script adds below the md breakpoint, or one the page writes |
date-picker-footerplf:date-picker-footer | Part | The panel's buttons |
date-picker-summaryplf:date-picker-summary | Part | The footer text that shows the draft |
date-picker-panel-rangeplf:date-picker-panel-range | Modifier | The wider range panel |
Default
Give both native inputs the same min and max.
<div class="date-picker" data-plf-date-picker data-plf-mode="range">
<div class="date-picker-inputs">
<label class="field date-picker-field" for="period-start">
<span class="field-label">Start date</span>
<input class="input" id="period-start" name="period-start" type="date" min="2026-01-01" max="2027-12-31">
</label>
<label class="field date-picker-field" for="period-end">
<span class="field-label">End date</span>
<input class="input" id="period-end" name="period-end" type="date" min="2026-01-01" max="2027-12-31">
</label>
</div>
<div class="date-picker-controls" hidden>
<div class="popover" data-plf-popover data-plf-align="start">
<div class="field">
<label class="field-label" for="period-text">Reporting period</label>
<div class="input-group">
<button type="button" class="input-group-action input-group-addon" aria-label="Open calendar"></button>
<input class="input-group-control" id="period-text" type="text" size="27">
</div>
</div>
<div class="popover-content date-picker-panel date-picker-panel-range" aria-label="Choose reporting period" hidden>
<div class="date-picker-body">
<div class="date-picker-presets" role="group" aria-label="Reporting period presets">
<button type="button" class="btn btn-ghost btn-sm" data-plf-date-picker-preset="today">Today</button>
<button type="button" class="btn btn-ghost btn-sm" data-plf-date-picker-preset="yesterday">Yesterday</button>
<button type="button" class="btn btn-ghost btn-sm" data-plf-date-picker-preset="last-7-days">Last 7 days</button>
<button type="button" class="btn btn-ghost btn-sm" data-plf-date-picker-preset="last-30-days">Last 30 days</button>
<button type="button" class="btn btn-ghost btn-sm" data-plf-date-picker-preset="this-month">This month</button>
<button type="button" class="btn btn-ghost btn-sm" data-plf-date-picker-preset="last-month">Last month</button>
</div>
<div class="calendar" data-plf-calendar data-plf-today="2026-10-04"></div>
</div>
<div class="date-picker-footer">
<span class="date-picker-summary" data-plf-date-picker-summary>No dates selected</span>
<button type="button" class="btn btn-ghost btn-sm" data-plf-date-picker-clear>Clear</button>
<button type="button" class="btn btn-outline btn-sm" data-plf-popover-close>Cancel</button>
<button type="button" class="btn btn-primary btn-sm" data-plf-date-picker-apply>Apply</button>
</div>
</div>
</div>
</div>
</div><div class="plf:date-picker" data-plf-date-picker data-plf-mode="range">
<div class="plf:date-picker-inputs">
<label class="plf:field plf:date-picker-field" for="period-start">
<span class="plf:field-label">Start date</span>
<input class="plf:input" id="period-start" name="period-start" type="date" min="2026-01-01" max="2027-12-31">
</label>
<label class="plf:field plf:date-picker-field" for="period-end">
<span class="plf:field-label">End date</span>
<input class="plf:input" id="period-end" name="period-end" type="date" min="2026-01-01" max="2027-12-31">
</label>
</div>
<div class="plf:date-picker-controls" hidden>
<div class="plf:popover" data-plf-popover data-plf-align="start">
<div class="plf:field">
<label class="plf:field-label" for="period-text">Reporting period</label>
<div class="plf:input-group">
<button type="button" class="plf:input-group-action plf:input-group-addon" aria-label="Open calendar"></button>
<input class="plf:input-group-control" id="period-text" type="text" size="27">
</div>
</div>
<div class="plf:popover-content plf:date-picker-panel plf:date-picker-panel-range" aria-label="Choose reporting period" hidden>
<div class="plf:date-picker-body">
<div class="plf:date-picker-presets" role="group" aria-label="Reporting period presets">
<button type="button" class="plf:btn plf:btn-ghost plf:btn-sm" data-plf-date-picker-preset="today">Today</button>
<button type="button" class="plf:btn plf:btn-ghost plf:btn-sm" data-plf-date-picker-preset="yesterday">Yesterday</button>
<button type="button" class="plf:btn plf:btn-ghost plf:btn-sm" data-plf-date-picker-preset="last-7-days">Last 7 days</button>
<button type="button" class="plf:btn plf:btn-ghost plf:btn-sm" data-plf-date-picker-preset="last-30-days">Last 30 days</button>
<button type="button" class="plf:btn plf:btn-ghost plf:btn-sm" data-plf-date-picker-preset="this-month">This month</button>
<button type="button" class="plf:btn plf:btn-ghost plf:btn-sm" data-plf-date-picker-preset="last-month">Last month</button>
</div>
<div class="plf:calendar" data-plf-calendar data-plf-today="2026-10-04"></div>
</div>
<div class="plf:date-picker-footer">
<span class="plf:date-picker-summary" data-plf-date-picker-summary>No dates selected</span>
<button type="button" class="plf:btn plf:btn-ghost plf:btn-sm" data-plf-date-picker-clear>Clear</button>
<button type="button" class="plf:btn plf:btn-outline plf:btn-sm" data-plf-popover-close>Cancel</button>
<button type="button" class="plf:btn plf:btn-primary plf:btn-sm" data-plf-date-picker-apply>Apply</button>
</div>
</div>
</div>
</div>
</div>Nights
The script counts the nights from plf:date-picker:change, as a booking form does.
Choose your check-in and check-out dates.
<div class="date-picker" id="stay-dates" data-plf-date-picker data-plf-mode="range">
<div class="date-picker-inputs">
<label class="field date-picker-field" for="stay-check-in">
<span class="field-label">Check-in</span>
<input class="input" id="stay-check-in" name="check-in" type="date" min="2026-10-04" max="2027-12-31">
</label>
<label class="field date-picker-field" for="stay-check-out">
<span class="field-label">Check-out</span>
<input class="input" id="stay-check-out" name="check-out" type="date" min="2026-10-04" max="2027-12-31">
</label>
</div>
<div class="date-picker-controls" hidden>
<div class="popover" data-plf-popover data-plf-align="start">
<div class="field">
<label class="field-label" for="stay-text">Stay</label>
<div class="input-group">
<button type="button" class="input-group-action input-group-addon" aria-label="Open calendar"></button>
<input class="input-group-control" id="stay-text" type="text" size="27">
</div>
</div>
<div class="popover-content date-picker-panel date-picker-panel-range" aria-label="Choose your stay" hidden>
<div class="date-picker-body">
<div class="calendar" data-plf-calendar data-plf-today="2026-10-04"></div>
</div>
<div class="date-picker-footer">
<span class="date-picker-summary" data-plf-date-picker-summary>No dates selected</span>
<button type="button" class="btn btn-ghost btn-sm" data-plf-date-picker-clear>Clear</button>
<button type="button" class="btn btn-outline btn-sm" data-plf-popover-close>Cancel</button>
<button type="button" class="btn btn-primary btn-sm" data-plf-date-picker-apply>Apply</button>
</div>
</div>
</div>
</div>
</div>
<p class="text-sm" id="stay-nights" role="status">Choose your check-in and check-out dates.</p>
<script>
const nights = document.getElementById('stay-nights');
document.getElementById('stay-dates').addEventListener('plf:date-picker:change', (event) => {
const { start, end } = event.detail.state.value;
const count = start && end ? (Date.parse(end) - Date.parse(start)) / 86400000 : 0;
nights.textContent = count ? `${count} ${count === 1 ? 'night' : 'nights'}` : 'Choose your check-in and check-out dates.';
});
</script><div class="plf:date-picker" id="stay-dates" data-plf-date-picker data-plf-mode="range">
<div class="plf:date-picker-inputs">
<label class="plf:field plf:date-picker-field" for="stay-check-in">
<span class="plf:field-label">Check-in</span>
<input class="plf:input" id="stay-check-in" name="check-in" type="date" min="2026-10-04" max="2027-12-31">
</label>
<label class="plf:field plf:date-picker-field" for="stay-check-out">
<span class="plf:field-label">Check-out</span>
<input class="plf:input" id="stay-check-out" name="check-out" type="date" min="2026-10-04" max="2027-12-31">
</label>
</div>
<div class="plf:date-picker-controls" hidden>
<div class="plf:popover" data-plf-popover data-plf-align="start">
<div class="plf:field">
<label class="plf:field-label" for="stay-text">Stay</label>
<div class="plf:input-group">
<button type="button" class="plf:input-group-action plf:input-group-addon" aria-label="Open calendar"></button>
<input class="plf:input-group-control" id="stay-text" type="text" size="27">
</div>
</div>
<div class="plf:popover-content plf:date-picker-panel plf:date-picker-panel-range" aria-label="Choose your stay" hidden>
<div class="plf:date-picker-body">
<div class="plf:calendar" data-plf-calendar data-plf-today="2026-10-04"></div>
</div>
<div class="plf:date-picker-footer">
<span class="plf:date-picker-summary" data-plf-date-picker-summary>No dates selected</span>
<button type="button" class="plf:btn plf:btn-ghost plf:btn-sm" data-plf-date-picker-clear>Clear</button>
<button type="button" class="plf:btn plf:btn-outline plf:btn-sm" data-plf-popover-close>Cancel</button>
<button type="button" class="plf:btn plf:btn-primary plf:btn-sm" data-plf-date-picker-apply>Apply</button>
</div>
</div>
</div>
</div>
</div>
<p class="plf:text-sm" id="stay-nights" role="status">Choose your check-in and check-out dates.</p>
<script>
const nights = document.getElementById('stay-nights');
document.getElementById('stay-dates').addEventListener('plf:date-picker:change', (event) => {
const { start, end } = event.detail.state.value;
const count = start && end ? (Date.parse(end) - Date.parse(start)) / 86400000 : 0;
nights.textContent = count ? `${count} ${count === 1 ? 'night' : 'nights'}` : 'Choose your check-in and check-out dates.';
});
</script>JavaScript
Date Range Picker is the range mode of the Date Picker extension, with the same methods, events and keys and a {start, end} value; calendar edits fire the Calendar events until Apply. The Full script (pelatform-ui.min.js) and the extension scripts after it start every component on page load, with no code of your own; with Core and single files, the last line starts them. For markup you add later, see Dynamic content.
<link rel="stylesheet" href="pelatform-ui.min.css">
<link rel="stylesheet" href="extensions/calendar.min.css">
<link rel="stylesheet" href="extensions/date-picker.min.css">
<script src="pelatform-ui.min.js" defer></script>
<script src="extensions/calendar.min.js" defer></script>
<script src="extensions/date-picker.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.min.css">
<link rel="stylesheet" href="components/button.min.css">
<link rel="stylesheet" href="components/form.min.css">
<link rel="stylesheet" href="components/popover.min.css">
<link rel="stylesheet" href="components/select.min.css">
<link rel="stylesheet" href="extensions/calendar.min.css">
<link rel="stylesheet" href="extensions/date-picker.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/popover.min.js" defer></script>
<script src="components/select.min.js" defer></script>
<script src="extensions/calendar.min.js" defer></script>
<script src="extensions/date-picker.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script><link rel="stylesheet" href="pelatform-ui.prefixed.min.css">
<link rel="stylesheet" href="extensions/calendar.prefixed.min.css">
<link rel="stylesheet" href="extensions/date-picker.prefixed.min.css">
<script src="pelatform-ui.min.js" defer></script>
<script src="extensions/calendar.min.js" defer></script>
<script src="extensions/date-picker.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.prefixed.min.css">
<link rel="stylesheet" href="components/button.prefixed.min.css">
<link rel="stylesheet" href="components/form.prefixed.min.css">
<link rel="stylesheet" href="components/popover.prefixed.min.css">
<link rel="stylesheet" href="components/select.prefixed.min.css">
<link rel="stylesheet" href="extensions/calendar.prefixed.min.css">
<link rel="stylesheet" href="extensions/date-picker.prefixed.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/popover.min.js" defer></script>
<script src="components/select.min.js" defer></script>
<script src="extensions/calendar.min.js" defer></script>
<script src="extensions/date-picker.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script>Hooks
These hooks add to or replace the Date Picker hooks.
| Attribute | Purpose |
|---|---|
data-plf-mode="range" |
On the container; the nested calendar inherits it and shows two months, one below the md breakpoint |
<input type="date"> |
Two named native inputs outside the Popover, the start and then the end, with the same min and max; their wrapper, the container’s child around them, hides once the text field works |
data-plf-popover |
Holds the field, its first child, and the panel, written hidden. The field holds the calendar button, the Popover’s trigger, and one unnamed, labeled text input for DD/MM/YYYY – DD/MM/YYYY, or one for each date. Unless written, the script gives it that placeholder and no autofill |
data-plf-date-picker-apply |
Required; the button that accepts the draft of calendar clicks and presets. Cancel keeps the accepted dates |
data-plf-date-picker-preset |
Optional buttons: today, yesterday, last-7-days, last-30-days, this-month or last-month, counted from the calendar’s today |
data-plf-preset-label, data-plf-custom-label |
On the container: the label of the preset select the script adds from the buttons, shown instead of them below the md breakpoint, and its first option; Quick range and Custom range by default. A <select> written in the panel with one empty option and the preset values replaces it |
data-plf-date-picker-summary |
Optional footer text that shows the draft; its own text shows when empty |
CSS variables
The panel also uses the Date Picker variables.
| Variable | Default |
|---|---|
--plf-date-picker-width |
48rem (768px); 20rem (320px) below the md breakpoint |
--plf-date-picker-preset-width |
9rem (144px), the preset sidebar |