Range Calendar
Range Calendar widgets are Input Fields that allow the user to visualize and select an inclusive date range (start date and end date). Each completed range is displayed as a pill that can be removed, or edited in place with allowEdit.
import { gui } from '@golemui/gui-shared';
export default [ gui.inputs.rangeCalendar('vacationDates'),];{ "$schema": "https://golemui.com/schemas/form.schema.json", "form": [ { "kind": "input", "type": "rangeCalendar", "path": "vacationDates" } ]}Use these props to customize your Range Calendar widget. Range Calendars share all properties with standard Calendars.
| prop | type | description |
|---|---|---|
allowEdit | boolean | Enables selecting and editing pills in place. See Editing Pills. Defaults to false |
cancelEditLabel | string | Localizable | Tooltip of the pill’s cancel icon while editing. Defaults to Cancel |
confirmEditLabel | string | Localizable | Tooltip of the pill’s confirm icon while editing. Defaults to Confirm |
disabledDateRangeMessage | string | Localizable | Error surfaced when a selected range spans one or more disabled days. Defaults to Invalid date: date is within a disabled range. |
disabledRanges | array | Array of objects ({ start: string, end?: string }) defining disabled date ranges |
editAriaLabel | string | Localizable | Edit hint joined into a selectable pill’s aria-description; {label} is replaced with the range’s label. Defaults to Edit range {label} |
editCancelledMessage | string | Localizable | Screen-reader announcement when an edit is cancelled. Defaults to Edit cancelled. |
editCommittedMessage | string | Localizable | Screen-reader announcement when an edit commits; {label} carries the resulting range. Defaults to Range updated to {label}. |
editLabel | string | Localizable | Tooltip of the pill’s edit icon. Defaults to Edit |
editStartedMessage | string | Localizable | Screen-reader announcement when an edit starts; {label} carries the range. Defaults to Editing range {label}. |
hint | string | A description to display below the range calendar |
maxDate | string | Maximum allowable date in ISO format |
minDate | string | Minimum allowable date in ISO format |
nextMonthAriaLabel | string | Accessible label for the next month navigation button |
numberOfMonths | number | Number of months to display simultaneously. Defaults to 2 for range calendars |
prevMonthAriaLabel | string | Accessible label for the previous month navigation button |
removePillAriaLabel | string | Accessible label for the remove button on date range pills |
selectYearAriaLabel | string | Accessible label for the year-selector toggle button in the calendar header; the current year is appended. Defaults to Select year |
yearGridAriaLabel | string | Accessible label for the year-selection grid. Defaults to Year selection |
Use the property hint to add a description to the date range selection.
import { gui } from '@golemui/gui-shared';
export default [ gui.inputs.rangeCalendar('vacationDates', { hint: 'Please select the start and end dates for your vacation', label: 'Vacation Dates', }),];{ "$schema": "https://golemui.com/schemas/form.schema.json", "form": [ { "kind": "input", "type": "rangeCalendar", "path": "vacationDates", "props": { "hint": "Please select the start and end dates for your vacation" }, "label": "Vacation Dates" } ]}Min and Max Dates
Section titled “Min and Max Dates”Use the properties minDate and maxDate to specify the boundaries for selectable dates.
import { gui } from '@golemui/gui-shared';
export default [ gui.inputs.rangeCalendar('vacationDates', { minDate: '2024-06-01T00:00:00.000Z', maxDate: '2024-08-31T23:59:59.999Z', defaultValue: [ { start: '2024-06-21', }, ], }),];{ "$schema": "https://golemui.com/schemas/form.schema.json", "form": [ { "kind": "input", "type": "rangeCalendar", "path": "vacationDates", "defaultValue": [ { "start": "2024-06-21" } ], "props": { "minDate": "2024-06-01T00:00:00.000Z", "maxDate": "2024-08-31T23:59:59.999Z" } } ]}Number of Months
Section titled “Number of Months”Use the property numberOfMonths to display multiple months side-by-side to ease selection of larger spans.
import { gui } from '@golemui/gui-shared';
export default [ gui.inputs.rangeCalendar('vacationDates', { numberOfMonths: 2, }),];{ "$schema": "https://golemui.com/schemas/form.schema.json", "form": [ { "kind": "input", "type": "rangeCalendar", "path": "vacationDates", "props": { "numberOfMonths": 2 } } ]}Disabled Ranges
Section titled “Disabled Ranges”Use the property disabledRanges to define dates which cannot be highlighted as part of a range. A selected range that spans one or more disabled days is rejected as a whole (no pill is added) and an error is thrown; customize (and localize) the error shown in that case with disabledDateRangeMessage.
import { gui } from '@golemui/gui-shared';
export default [ gui.inputs.rangeCalendar('vacationDates', { disabledRanges: [ { start: '2024-07-04T00:00:00.000Z', end: '2024-07-07T23:59:59.999Z', }, ], disabledDateRangeMessage: 'Selection can\'t include blocked days', defaultValue: [ { start: '2024-07-21', end: '2024-07-25', }, ], }),];{ "$schema": "https://golemui.com/schemas/form.schema.json", "form": [ { "kind": "input", "type": "rangeCalendar", "path": "vacationDates", "defaultValue": [ { "start": "2024-07-21", "end": "2024-07-25" } ], "props": { "disabledRanges": [ { "start": "2024-07-04T00:00:00.000Z", "end": "2024-07-07T23:59:59.999Z" } ], "disabledDateRangeMessage": "Selection can't include blocked days" } } ]}Custom Icons
Section titled “Custom Icons”Use prevMonthIcon, nextMonthIcon, prevMonthAriaLabel and nextMonthAriaLabel to customize the navigation buttons.
import { gui } from '@golemui/gui-shared';
export default [ gui.inputs.rangeCalendar('dates', { prevMonthIcon: 'chevron_left', nextMonthIcon: 'chevron_right', prevMonthAriaLabel: 'Go to previous month', nextMonthAriaLabel: 'Go to next month', label: 'Custom Icons Range Calendar', uid: 'range-calendar-icons', }),];{ "$schema": "https://golemui.com/schemas/form.schema.json", "form": [ { "uid": "range-calendar-icons", "kind": "input", "type": "rangeCalendar", "path": "dates", "label": "Custom Icons Range Calendar", "props": { "prevMonthIcon": "chevron_left", "nextMonthIcon": "chevron_right", "prevMonthAriaLabel": "Go to previous month", "nextMonthAriaLabel": "Go to next month" } } ]}Aria Labels
Section titled “Aria Labels”Use prevMonthAriaLabel, nextMonthAriaLabel and removePillAriaLabel to provide accessible labels for the navigation buttons and the remove button on date range pills.
import { gui } from '@golemui/gui-shared';
export default [ gui.inputs.rangeCalendar('dates', { prevMonthAriaLabel: 'Go to previous month', nextMonthAriaLabel: 'Go to next month', removePillAriaLabel: 'Remove date range', label: 'Range Calendar with Aria Labels', uid: 'range-calendar-aria-labels', }),];{ "$schema": "https://golemui.com/schemas/form.schema.json", "form": [ { "uid": "range-calendar-aria-labels", "kind": "input", "type": "rangeCalendar", "path": "dates", "label": "Range Calendar with Aria Labels", "props": { "prevMonthAriaLabel": "Go to previous month", "nextMonthAriaLabel": "Go to next month", "removePillAriaLabel": "Remove date range" } } ]}Editing Pills
Section titled “Editing Pills”Use the property allowEdit to let the user change a committed range in place instead of removing it and picking 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 day grid. While you re-pick, the pill’s label previews the new value. 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.
Here the calendar itself is the edit surface. Selecting a pill dims the other committed ranges in the day grid, and editing parks the pill’s span as the in-progress selection: day picks reshape it without committing until the pill’s check icon confirms. Leaving the widget with a complete, changed span also commits it. Escape is layered: the first press cancels the edit, the second clears the selection.
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.
import { gui } from '@golemui/gui-shared';
export default [ gui.inputs.rangeCalendar('editableVacations', { allowEdit: true, label: 'Vacations', defaultValue: [ { start: '2026-09-07', end: '2026-09-11', }, { start: '2026-09-21', end: '2026-09-25', }, ], }),];{ "$schema": "https://golemui.com/schemas/form.schema.json", "form": [ { "kind": "input", "type": "rangeCalendar", "path": "editableVacations", "label": "Vacations", "defaultValue": [ { "start": "2026-09-07", "end": "2026-09-11" }, { "start": "2026-09-21", "end": "2026-09-25" } ], "props": { "allowEdit": true } } ]}Styling
Section titled “Styling”Range Calendars can be styled as explained in the Styling Guide. They inherit all Calendar widget styles along with specialized range highlighting rules.
CSS Variables
Section titled “CSS Variables”Following you will find a list with the CSS Variables and a quick description of what you will style.
| CSS Variable | Description |
|---|---|
--gui-radius-md | Calendar container base radius |
--gui-radius-range | Border radius applied to the start and end of a selected range (calculated as double radius-md) |
--gui-bg-default | Calendar container background color |
--gui-border-default | Default border color and cell hover border color |
--gui-space-3 | Internal padding |
--gui-calendar-change-month-button-width | Width of the next/prev buttons |
--gui-calendar-change-month-button-height | Height of the next/prev buttons |
--gui-text-default | Default text and focus border color |
--gui-text-secondary | Day button hover background color |
--gui-intent-primary-active | ”Today” border highlight color |
--gui-intent-primary | Selected range and selected day background color |
--gui-bg-disabled | Disabled day background color |
--gui-pill-height | Pill height. 24px, 32px under pointer: coarse |
--gui-pill-action-size | Size of the edit, confirm, cancel and remove icons. 16px, 24px under pointer: coarse |
--gui-pill-action-hit | Hit area of each pill icon. 24px, 32px under pointer: coarse |
--gui-pill-font-size | Pill label font size. var(--gui-font-xs), var(--gui-font-sm) under pointer: coarse |
Anatomy
Section titled “Anatomy”This is the anatomy of the Range Calendar Widget in case you want to use your CSS styles.
<gui-range-calendar-input class="gui-calendar gui-field"> <gui-range-calendar allow-edit="" class="gui-field"> <label class="gui-label" for="fieldUid" id="fieldUid_calendar_label"><span class="gui-label__text">Vacations</span></label> <div class="gui-widget"> <div class="gui-calendar-input" role="group" id="fieldUid_calendar" aria-labelledby="fieldUid_calendar_label"> <div class="gui-visually-hidden" aria-live="polite"></div> <div class="gui-visually-hidden" aria-live="polite"></div> <gui-pills class="gui-range-calendar__pills"> <div class="gui-pills__strip-wrapper gui-pills--start-shadow gui-pills--end-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="0" 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="0" 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> </gui-pills> <div class="gui-calendar__container"> <button type="button" class="gui-button gui-calendar__month-button gui-calendar__month-button--prev" aria-label="Previous month"> <span class="gui-caret gui-caret--left" aria-hidden="true"></span> </button> <div class="gui-calendar__months-grid"> <div class="gui-calendar__panel"> <header class="gui-calendar__header"> <h2> <span class="gui-calendar__month-name">September</span> <button type="button" class="gui-calendar__year-selector" aria-expanded="false" aria-label="Select year, 2026"> <span class="gui-calendar__year-value">2026</span> <span class="gui-calendar__year-arrow" aria-hidden="true"> <span class="gui-caret" aria-hidden="true"></span> </span> </button> </h2> </header> <div class="gui-calendar__days-grid" role="grid" aria-label="September 2026"> <div role="row" class="gui-calendar__rows"> <span class="gui-calendar__weekday" role="columnheader">S</span> <span class="gui-calendar__weekday" role="columnheader">M</span> <span class="gui-calendar__weekday" role="columnheader">T</span> <!-- More span.gui-calendar__weekday --> </div> <div role="row" class="gui-calendar__rows"> <button type="button" role="gridcell" class="gui-calendar__day-button other-month" tabindex="-1" disabled="" aria-label="Sunday, August 30, 2026" data-date="2026-08-30" aria-selected="false" > 30 </button> <button type="button" role="gridcell" class="gui-calendar__day-button other-month" tabindex="-1" disabled="" aria-label="Monday, August 31, 2026" data-date="2026-08-31" aria-selected="false" > 31 </button> <button type="button" role="gridcell" class="gui-calendar__day-button" tabindex="-1" aria-label="Tuesday, September 1, 2026" data-date="2026-09-01" aria-selected="false" > 1 </button> <!-- More button.gui-calendar__day-button --> </div> <div role="row" class="gui-calendar__rows"> <button type="button" role="gridcell" class="gui-calendar__day-button" tabindex="-1" aria-label="Sunday, September 6, 2026" data-date="2026-09-06" aria-selected="false" > 6 </button> <button type="button" role="gridcell" class="gui-calendar__day-button range-start" tabindex="0" aria-label="Monday, September 7, 2026" data-date="2026-09-07" aria-selected="true" > 7 </button> <button type="button" role="gridcell" class="gui-calendar__day-button in-range" tabindex="-1" aria-label="Tuesday, September 8, 2026" data-date="2026-09-08" aria-selected="true" > 8 </button> <!-- More button.gui-calendar__day-button --> </div> <!-- More div.gui-calendar__rows --> </div> </div> </div> <button type="button" class="gui-button gui-calendar__month-button gui-calendar__month-button--next" aria-label="Next month"> <span class="gui-caret gui-caret--right" aria-hidden="true"></span> </button> </div> </div> </div> </gui-range-calendar></gui-range-calendar-input>