Skip to content
Forms, switch product

Range Date Picker

Range Date Picker widgets are Input Fields that let the user enter one or more date ranges in a single compact field: they can type the ranges using their keyboard or open a drop-down calendar popover to select them visually. Clicking a pill or pressing Enter navigates the calendar to that range’s month; with allowEdit it also selects the pill so the range can be edited in place. For an always-visible inline variant, use the Range Calendar.

range-date-picker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDatePicker('dateRanges', {
label: 'Date Ranges',
}),
];
range-date-picker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDatePicker",
"path": "dateRanges",
"label": "Date Ranges"
}
]
}

Use these props to customize your Range Date Picker widget.

proptypedescription
allowEditbooleanEnables selecting and editing pills in place. See Editing Pills. Defaults to false
cancelEditLabelstring | LocalizableTooltip of the pill’s cancel icon while editing. Defaults to Cancel
confirmEditLabelstring | LocalizableTooltip of the pill’s confirm icon while editing. Defaults to Confirm
dayAriaLabelstringAria label for the day segment input. Defaults to Day
disabledDateRangeMessagestring | LocalizableError message shown when a typed date falls inside a disabled range
disabledRangesarrayArray of objects ({ start: string, end?: string }) defining disabled date ranges
editAriaLabelstring | LocalizableEdit hint joined into a selectable pill’s aria-description; {label} is replaced with the range’s label. Defaults to Edit range {label}
editCancelledMessagestring | LocalizableScreen-reader announcement when an edit is cancelled. Defaults to Edit cancelled.
editCommittedMessagestring | LocalizableScreen-reader announcement when an edit commits; {label} carries the resulting range. Defaults to Range updated to {label}.
editLabelstring | LocalizableTooltip of the pill’s edit icon. Defaults to Edit
editStartedMessagestring | LocalizableScreen-reader announcement when an edit starts; {label} carries the range. Defaults to Editing range {label}.
endDateAriaLabelstringAria label for the end date field group. Defaults to End date
hintstringA description to display below the input fields
iconstringCustom icon class to display inside the input visually (e.g. fas fa-calendar)
incompleteMessagestring | LocalizableError message shown when focus leaves the widget with a partially filled date behind; the value goes to null so validators report it
invalidDateMessagestring | LocalizableError message shown when a typed date does not exist, e.g. February 30
maxDatestringLatest allowed date (ISO date, inclusive); later calendar days render disabled
maxDateMessagestring | LocalizableError message shown when a typed date is after maxDate
minDatestringEarliest allowed date (ISO date, inclusive); earlier calendar days render disabled
minDateMessagestring | LocalizableError message shown when a typed date is before minDate
monthAriaLabelstringAria label for the month segment input. Defaults to Month
nextMonthAriaLabelstringARIA label for the next month button
nextMonthIconstringCustom CSS class for the “next month” button inside the calendar
numberOfMonthsnumberNumber of months to display simultaneously in the popover. Defaults to 1
prevMonthAriaLabelstringARIA label for the previous month button
prevMonthIconstringCustom CSS class for the “previous month” button inside the calendar
removePillAriaLabelstringAria label for the remove pill action. Defaults to Remove date
selectYearAriaLabelstringAria label for the year-selector toggle button in the calendar header; the current year is appended. Defaults to Select year
separatorstringThe separator between start and end date fields. Defaults to -
startDateAriaLabelstringAria label for the start date field group. Defaults to Start date
toggleAriaLabelstringAria label for the popup toggle button. Defaults to Show calendar
yearAriaLabelstringAria label for the year segment input. Defaults to Year
yearGridAriaLabelstringAria label for the year-selection grid. Defaults to Year selection

Use the property hint to add descriptive text.

range-date-picker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDatePicker('dateRanges', {
hint: 'Select one or more date ranges from the calendar.',
label: 'Date Ranges',
}),
];
range-date-picker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDatePicker",
"path": "dateRanges",
"label": "Date Ranges",
"props": {
"hint": "Select one or more date ranges from the calendar."
}
}
]
}

Use the property icon to add an icon, which appears next to the toggle chevron.

range-date-picker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDatePicker('dateRanges', {
icon: 'calendar_month',
label: 'Date Ranges',
}),
];
range-date-picker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDatePicker",
"path": "dateRanges",
"label": "Date Ranges",
"props": {
"icon": "calendar_month"
}
}
]
}

Use the properties prevMonthIcon, nextMonthIcon, prevMonthAriaLabel, and nextMonthAriaLabel to customize the navigation buttons within the calendar popover.

range-date-picker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDatePicker('dateRanges', {
prevMonthIcon: 'chevron_left',
nextMonthIcon: 'chevron_right',
prevMonthAriaLabel: 'Go to previous month',
nextMonthAriaLabel: 'Go to next month',
label: 'Date Ranges',
}),
];
range-date-picker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDatePicker",
"path": "dateRanges",
"label": "Date Ranges",
"props": {
"prevMonthIcon": "chevron_left",
"nextMonthIcon": "chevron_right",
"prevMonthAriaLabel": "Go to previous month",
"nextMonthAriaLabel": "Go to next month"
}
}
]
}

Use the property separator to customize the text displayed between the start date and end date fields. By default the separator is -.

range-date-picker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDatePicker('dateRanges', {
separator: 'to',
label: 'Date Ranges',
}),
];
range-date-picker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDatePicker",
"path": "dateRanges",
"label": "Date Ranges",
"props": {
"separator": "to"
}
}
]
}

Use the properties removePillAriaLabel, startDateAriaLabel and endDateAriaLabel to customize the accessibility labels for screen readers. These properties are localizable.

range-date-picker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDatePicker('dateRanges', {
removePillAriaLabel: 'Delete range',
startDateAriaLabel: 'From date',
endDateAriaLabel: 'To date',
label: 'Date Ranges',
}),
];
range-date-picker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDatePicker",
"path": "dateRanges",
"label": "Date Ranges",
"props": {
"removePillAriaLabel": "Delete range",
"startDateAriaLabel": "From date",
"endDateAriaLabel": "To date"
}
}
]
}

Use minDate and maxDate (ISO dates, both inclusive) to bound the selectable range, and disabledRanges to disable specific date blocks. Out-of-range days render disabled in the calendar popover, and a typed date that violates a boundary raises an input error; customize (and localize) the messages with minDateMessage, maxDateMessage and disabledDateRangeMessage.

range-date-picker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDatePicker('holidayPeriods', {
hint: 'Plan holidays between 2026-02-01 and 2026-07-31',
minDate: '2026-02-01',
maxDate: '2026-07-31',
disabledRanges: [
{
start: '2026-02-09',
end: '2026-02-10',
},
{
start: '2026-02-17',
},
],
minDateMessage: 'No holidays before February 2026',
maxDateMessage: 'No holidays after July 2026',
disabledDateRangeMessage: 'This date is not available',
label: 'Holiday Periods',
}),
];
range-date-picker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDatePicker",
"path": "holidayPeriods",
"label": "Holiday Periods",
"props": {
"hint": "Plan holidays between 2026-02-01 and 2026-07-31",
"minDate": "2026-02-01",
"maxDate": "2026-07-31",
"disabledRanges": [
{
"start": "2026-02-09",
"end": "2026-02-10"
},
{
"start": "2026-02-17"
}
],
"minDateMessage": "No holidays before February 2026",
"maxDateMessage": "No holidays after July 2026",
"disabledDateRangeMessage": "This date is not available"
}
}
]
}

Use the property allowEdit to let the user change a committed range in place instead of removing it and typing it again. Click a pill, or arrow onto it, to select it; the selection reveals a pencil icon next to the remove icon. The pencil, or F2 or E on the focused pill, loads the range back into the segments and moves focus to the first start segment. While you type, the pill’s label previews the new value. Enter in the segments or the pill’s check icon confirms the replacement; Escape or the cross icon cancels it and keeps the pill selected. A confirmed range that overlaps a neighbour merges into it, and confirming an unchanged range is treated as a cancel. Selecting is not a commit: the form value only changes on confirm.

Selecting a pill navigates the popover calendar to that range’s month and dims the other committed ranges. During an edit, day picks reshape the range without committing; Enter in the segments or the pill’s check icon confirms the replacement. Escape closes an open popover first, then cancels the edit.

On touch devices, where the pills collapse into the count bubble, the pencil is always visible inside the pills dropdown, and the pills and their icons grow to the pointer: coarse sizes listed under CSS Variables.

The tooltips and screen-reader announcements of the flow are localizable through editLabel, confirmEditLabel, cancelEditLabel, editAriaLabel, editStartedMessage, editCommittedMessage and editCancelledMessage. A {label} token in editAriaLabel, editStartedMessage and editCommittedMessage is replaced with the range’s display label by the widget itself, single braces on purpose, so the form’s {{ }} localization interpolation never consumes it.

range-date-picker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDatePicker('editableBookings', {
allowEdit: true,
separator: 'to',
label: 'Bookings',
defaultValue: [
{
start: '2026-09-07',
end: '2026-09-11',
},
{
start: '2026-09-21',
end: '2026-09-25',
},
],
}),
];
range-date-picker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDatePicker",
"path": "editableBookings",
"label": "Bookings",
"defaultValue": [
{
"start": "2026-09-07",
"end": "2026-09-11"
},
{
"start": "2026-09-21",
"end": "2026-09-25"
}
],
"props": {
"allowEdit": true,
"separator": "to"
}
}
]
}

Range Date Pickers can be styled as explained in the Styling Guide. The typed field and the popover calendar each have their own styling variables.

Following you will find a list with the CSS Variables specific to the Range Date Picker popover positioning and toggle, plus those inherited from its sub-widgets.

CSS VariableDescription
--gui-radius-mdInteractive calendar container, day button, and pill border radius
--gui-bg-defaultInteractive calendar background color
--gui-border-defaultInteractive calendar border color, hover day border, pills wrapper border
--gui-space-3Internal padding within the calendar view and day buttons
--gui-text-defaultInput text color and day buttons text color
--gui-bg-disabledDisabled day background color
--gui-intent-primarySelected day and pill background color
--gui-intent-primary-hoverToday’s day border color
--gui-intent-errorBorder and focus shadow color when invalid
--gui-border-focusBorder color when a pill or input is focused
--gui-shadow-focusBox shadow when a pill or input is focused
--gui-pill-heightPill height. 24px, 32px under pointer: coarse
--gui-pill-action-sizeSize of the edit, confirm, cancel and remove icons. 16px, 24px under pointer: coarse
--gui-pill-action-hitHit area of each pill icon. 24px, 32px under pointer: coarse
--gui-pill-font-sizePill label font size. var(--gui-font-xs), var(--gui-font-sm) under pointer: coarse

This is the anatomy of the Range Date Picker Widget in case you want to use your CSS styles.

range-date-picker-anatomy.html
<gui-range-date-picker-input class="gui-range-date-picker gui-field">
<gui-range-date-picker allow-edit="">
<span class="gui-label" id="fieldUid_label"><span class="gui-label__text">Bookings</span></span>
<div class="gui-widget">
<gui-range-date id="date-input" class="gui-field">
<div class="gui-widget">
<div class="gui-visually-hidden" aria-live="polite"></div>
<div role="group" class="gui-widget-input gui-parts-ring gui-range-date-input" aria-label="Date range input">
<gui-pills class="gui-range-date-input__pills">
<div class="gui-pills__strip-wrapper gui-pills--end-shadow gui-pills--start-shadow">
<div class="gui-pills__strip" role="toolbar" tabindex="-1" aria-label="Selected date ranges">
<span class="gui-sentinel gui-sentinel__start"></span>
<button
type="button"
class="gui-pills__pill gui-pills__pill--clickable"
tabindex="-1"
aria-pressed="false"
aria-label="09/07/2026 - 09/11/2026"
aria-description="Edit range 09/07/2026 - 09/11/2026. Remove date"
>
<span class="gui-pills__pill-text">09/07/2026 - 09/11/2026</span>
<span aria-hidden="true" class="gui-pills__pill-action gui-pills__pill-action--edit" title="Edit">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 256 256"
fill="currentColor"
aria-hidden="true"
>
<path d="M229.66,58.34l-32-…"></path>
</svg>
</span>
<span class="gui-pills__pill-remove" aria-hidden="true">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 256 256"
fill="currentColor"
aria-hidden="true"
>
<path d="M165.66,101.66,139…"></path>
</svg>
</span>
</button>
<button
type="button"
class="gui-pills__pill gui-pills__pill--clickable"
tabindex="-1"
aria-pressed="false"
aria-label="09/21/2026 - 09/25/2026"
aria-description="Edit range 09/21/2026 - 09/25/2026. Remove date"
>
<span class="gui-pills__pill-text">09/21/2026 - 09/25/2026</span>
<span aria-hidden="true" class="gui-pills__pill-action gui-pills__pill-action--edit" title="Edit">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 256 256"
fill="currentColor"
aria-hidden="true"
>
<path d="M229.66,58.34l-32-…"></path>
</svg>
</span>
<span class="gui-pills__pill-remove" aria-hidden="true">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 256 256"
fill="currentColor"
aria-hidden="true"
>
<path d="M165.66,101.66,139…"></path>
</svg>
</span>
</button>
<span class="gui-sentinel gui-sentinel__end"></span>
</div>
</div>
<div class="gui-pills__compact">
<button
type="button"
aria-haspopup="true"
class="gui-pills__count"
aria-label="2 date ranges"
aria-expanded="false"
aria-controls="fieldUid_pills_dropdown"
>
2
</button>
</div>
</gui-pills>
<div class="gui-range-date-input__inputs">
<div class="gui-parts gui-range-date-input__field" role="group" aria-label="Start date">
<div class="gui-parts__touch-target gui-range-date-input__touch-target">
<input
type="text"
inputmode="numeric"
role="spinbutton"
autocomplete="off"
class="gui-parts__part gui-range-date-input__part"
data-type="month"
data-group="start"
maxlength="2"
placeholder="mm"
tabindex="0"
aria-label="Month"
aria-valuemin="1"
aria-valuemax="12"
/>
<div class="gui-parts__visual-underline gui-range-date-input__visual-underline"></div>
</div>
<span class="gui-range-date-input__separator">/</span>
<div class="gui-parts__touch-target gui-range-date-input__touch-target">
<input
type="text"
inputmode="numeric"
role="spinbutton"
autocomplete="off"
class="gui-parts__part gui-range-date-input__part"
data-type="day"
data-group="start"
maxlength="2"
placeholder="dd"
tabindex="-1"
aria-label="Day"
aria-valuemin="1"
aria-valuemax="31"
/>
<div class="gui-parts__visual-underline gui-range-date-input__visual-underline"></div>
</div>
<span class="gui-range-date-input__separator">/</span>
<div class="gui-parts__touch-target gui-range-date-input__touch-target">
<input
type="text"
inputmode="numeric"
role="spinbutton"
autocomplete="off"
class="gui-parts__part gui-range-date-input__part gui-parts__year gui-range-date-input__year"
data-type="year"
data-group="start"
maxlength="4"
placeholder="yyyy"
tabindex="-1"
aria-label="Year"
aria-valuemin="1900"
aria-valuemax="9999"
/>
<div class="gui-parts__visual-underline gui-range-date-input__visual-underline"></div>
</div>
</div>
<span class="gui-range-date-input__separator">to</span>
<div class="gui-parts gui-range-date-input__field" role="group" aria-label="End date">
<div class="gui-parts__touch-target gui-range-date-input__touch-target">
<input
type="text"
inputmode="numeric"
role="spinbutton"
autocomplete="off"
class="gui-parts__part gui-range-date-input__part"
data-type="month"
data-group="end"
maxlength="2"
placeholder="mm"
tabindex="-1"
aria-label="Month"
aria-valuemin="1"
aria-valuemax="12"
/>
<div class="gui-parts__visual-underline gui-range-date-input__visual-underline"></div>
</div>
<span class="gui-range-date-input__separator">/</span>
<div class="gui-parts__touch-target gui-range-date-input__touch-target">
<input
type="text"
inputmode="numeric"
role="spinbutton"
autocomplete="off"
class="gui-parts__part gui-range-date-input__part"
data-type="day"
data-group="end"
maxlength="2"
placeholder="dd"
tabindex="-1"
aria-label="Day"
aria-valuemin="1"
aria-valuemax="31"
/>
<div class="gui-parts__visual-underline gui-range-date-input__visual-underline"></div>
</div>
<span class="gui-range-date-input__separator">/</span>
<div class="gui-parts__touch-target gui-range-date-input__touch-target">
<input
type="text"
inputmode="numeric"
role="spinbutton"
autocomplete="off"
class="gui-parts__part gui-range-date-input__part gui-parts__year gui-range-date-input__year"
data-type="year"
data-group="end"
maxlength="4"
placeholder="yyyy"
tabindex="-1"
aria-label="Year"
aria-valuemin="1900"
aria-valuemax="9999"
/>
<div class="gui-parts__visual-underline gui-range-date-input__visual-underline"></div>
</div>
</div>
</div>
</div>
</div>
</gui-range-date>
<button
type="button"
class="gui-range-date-picker__arrow"
aria-haspopup="dialog"
aria-label="Show calendar"
aria-expanded="false"
aria-controls="fieldUid_popup"
>
<span class="gui-caret" aria-hidden="true"></span>
</button>
</div>
<ul class="gui-validator gui-validator--empty" id="fieldUid_errors" role="alert"></ul>
</gui-range-date-picker>
</gui-range-date-picker-input>