Skip to content
Forms, switch product

Range Date Time Calendar

Range Date Time Calendar widgets are Input Fields that let the user build one or more date-time ranges from an always-visible, multi-month calendar. The user picks a start day and an end day on the grid, then a start time and an end time from the two embedded time pickers below it; committing the end time adds the range as a removable pill, which allowEdit also makes editable in place.

The widget emits an array of { start, end } local ISO date-time strings (YYYY-MM-DDTHH:mm:ss), one entry per selected range. For a single date-time value, use the Date Time Calendar; for the compact popover variant with a typed input trigger, use the Range Date Time Picker.

range-datetime-calendar.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDateTimeCalendar('bookingSlots', {
label: 'Booking slots',
}),
];
range-datetime-calendar.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDateTimeCalendar",
"path": "bookingSlots",
"label": "Booking slots"
}
]
}

Use these props to customize your Range Date Time Calendar widget. It accepts date props (for the day grid) and time props (for the two pickers), all listed below. With numberOfMonths greater than 1, the time pickers render on the first panel only.

proptypedescription
allowCustomTimebooleanAllow typing a time in each picker; when false (default) times come only from the grid
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
dayCountAriaLabelstring | LocalizableAria label template for the per-day count badge; {count} token substituted. Defaults to {count} ranges
dayFormatstringHow day numbers are formatted. Defaults to numeric
disabledDayCountAriaLabelstring | LocalizableAria label template for the per-day disabled-spans badge; {count} token substituted. Defaults to {count} disabled ranges
disabledRangeMessagestring | LocalizableError shown when a selected range overlaps a disabled span
disabledRangesarrayArray of { start, end } date-time spans that render disabled (a whole day is 00:00:00–23:59:59)
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}.
endTimeLabelstring | LocalizableVisible heading on the end time picker. Defaults to End time
hintstringA description to display below the calendar
hourFormat'12' | '24'Force 12- or 24-hour entry. Defaults to the user’s locale
incompleteMessagestring | LocalizableError shown when focus leaves the widget with a half-finished range selection behind; committed pills stay untouched
maxDateTimestringLatest allowed instant (ISO date-time, inclusive)
maxDateTimeMessagestring | LocalizableError shown when a selection is after maxDateTime
minDateTimestringEarliest allowed instant (ISO date-time, inclusive)
minDateTimeMessagestring | LocalizableError shown when a selection is before minDateTime
minuteStepnumberGranularity of the time pickers
monthFormatstringHow the month heading is formatted. Defaults to long
nextMonthAriaLabelstringAccessible label for the next month navigation button
nextMonthIconstringCustom CSS class for the next month button
noAvailableTimesMessagestring | LocalizableMessage shown when the bounds yield no selectable times. Defaults to No available times
numberOfMonthsnumberNumber of months to display simultaneously. Defaults to 1
prevMonthAriaLabelstringAccessible label for the previous month navigation button
prevMonthIconstringCustom CSS class for the previous month button
removePillAriaLabelstringAria label for the remove pill action
selectYearAriaLabelstringAccessible label for the year-selector toggle button in the calendar header; the current year is appended. Defaults to Select year
startTimeLabelstring | LocalizableVisible heading on the start time picker. Defaults to Start time
weekdayFormatstringHow weekday headers are formatted. Defaults to narrow
yearGridAriaLabelstringAccessible label for the year-selection grid. Defaults to Year selection

Use the property hint to add a description below the calendar.

range-datetime-calendar.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDateTimeCalendar('bookingSlots', {
hint: 'Pick a day, then a start and end time to add a slot',
minuteStep: 30,
label: 'Booking slots',
}),
];
range-datetime-calendar.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDateTimeCalendar",
"path": "bookingSlots",
"label": "Booking slots",
"props": {
"hint": "Pick a day, then a start and end time to add a slot",
"minuteStep": 30
}
}
]
}

Use startTimeLabel and endTimeLabel to rename the headings on the two embedded time pickers (they default to Start time and End time).

range-datetime-calendar.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDateTimeCalendar('stay', {
startTimeLabel: 'Check-in',
endTimeLabel: 'Check-out',
minuteStep: 30,
label: 'Stay',
defaultValue: [
{
start: '2026-02-16T14:00:00',
end: '2026-02-18T09:30:00',
},
],
}),
];
range-datetime-calendar.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDateTimeCalendar",
"path": "stay",
"label": "Stay",
"defaultValue": [
{
"start": "2026-02-16T14:00:00",
"end": "2026-02-18T09:30:00"
}
],
"props": {
"startTimeLabel": "Check-in",
"endTimeLabel": "Check-out",
"minuteStep": 30
}
}
]
}

Use minDateTime and maxDateTime to bound the selectable instants (both inclusive). Days outside the range render disabled, and the time pickers are clamped on the boundary days. Customize (and localize) the out-of-bounds errors with minDateTimeMessage and maxDateTimeMessage.

range-datetime-calendar.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDateTimeCalendar('bookingSlots', {
minDateTime: '2026-02-01T09:00:00',
maxDateTime: '2026-07-31T18:00:00',
minuteStep: 30,
minDateTimeMessage: 'Bookings open on 1 Feb at 9:00',
maxDateTimeMessage: 'Bookings close on 31 Jul at 18:00',
label: 'Booking slots',
}),
];
range-datetime-calendar.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDateTimeCalendar",
"path": "bookingSlots",
"label": "Booking slots",
"props": {
"minDateTime": "2026-02-01T09:00:00",
"maxDateTime": "2026-07-31T18:00:00",
"minuteStep": 30,
"minDateTimeMessage": "Bookings open on 1 Feb at 9:00",
"maxDateTimeMessage": "Bookings close on 31 Jul at 18:00"
}
}
]
}

Use disabledRanges to grey out spans that cannot be part of a selection. A whole-day span runs 00:00:00–23:59:59 and disables the day on the grid; a partial-day span greys out the matching time slots and shows a disabled-count badge on that day. Selecting a range that overlaps a disabled span raises an input error whose message you set with disabledRangeMessage.

range-datetime-calendar.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDateTimeCalendar('bookingSlots', {
minuteStep: 30,
disabledRanges: [
{
start: '2026-02-09T00:00:00',
end: '2026-02-10T23:59:59',
},
{
start: '2026-02-17T13:00:00',
end: '2026-02-17T14:00:00',
},
],
disabledRangeMessage: 'That slot overlaps an unavailable time',
label: 'Booking slots',
}),
];
range-datetime-calendar.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDateTimeCalendar",
"path": "bookingSlots",
"label": "Booking slots",
"props": {
"minuteStep": 30,
"disabledRanges": [
{
"start": "2026-02-09T00:00:00",
"end": "2026-02-10T23:59:59"
},
{
"start": "2026-02-17T13:00:00",
"end": "2026-02-17T14:00:00"
}
],
"disabledRangeMessage": "That slot overlaps an unavailable time"
}
}
]
}

Use the property allowCustomTime to let the user type a time directly in each picker, in addition to picking a slot. Typed times are still validated against minDateTime, maxDateTime and disabledRanges.

range-datetime-calendar.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDateTimeCalendar('bookingSlots', {
allowCustomTime: true,
minuteStep: 30,
minDateTime: '2026-02-01T09:00:00',
maxDateTime: '2026-07-31T18:00:00',
label: 'Booking slots',
}),
];
range-datetime-calendar.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDateTimeCalendar",
"path": "bookingSlots",
"label": "Booking slots",
"props": {
"allowCustomTime": true,
"minuteStep": 30,
"minDateTime": "2026-02-01T09:00:00",
"maxDateTime": "2026-07-31T18:00:00"
}
}
]
}

Use the property numberOfMonths to display multiple months side-by-side to ease selection of larger spans. The time pickers render on the first panel only.

range-datetime-calendar.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDateTimeCalendar('bookingSlots', {
numberOfMonths: 2,
minuteStep: 30,
label: 'Booking slots',
defaultValue: [
{
start: '2026-02-16T14:00:00',
end: '2026-02-18T09:30:00',
},
],
}),
];
range-datetime-calendar.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDateTimeCalendar",
"path": "bookingSlots",
"label": "Booking slots",
"defaultValue": [
{
"start": "2026-02-16T14:00:00",
"end": "2026-02-18T09:30:00"
}
],
"props": {
"numberOfMonths": 2,
"minuteStep": 30
}
}
]
}

A day carrying more than one range shows a count badge, and a day with disabled spans shows a disabled-count badge. Use dayCountAriaLabel and disabledDayCountAriaLabel to set the accessible label templates; the {count} token is substituted with the number of ranges.

range-datetime-calendar.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDateTimeCalendar('bookingSlots', {
minuteStep: 30,
disabledRanges: [
{
start: '2026-02-17T13:00:00',
end: '2026-02-17T14:00:00',
},
],
dayCountAriaLabel: 'Number of slots taken: {count}',
disabledDayCountAriaLabel: 'Number of blocked slots: {count}',
label: 'Booking slots',
defaultValue: [
{
start: '2026-02-13T09:00:00',
end: '2026-02-13T11:00:00',
},
{
start: '2026-02-13T13:00:00',
end: '2026-02-13T15:00:00',
},
{
start: '2026-02-16T14:00:00',
end: '2026-02-18T09:30:00',
},
],
}),
];
range-datetime-calendar.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDateTimeCalendar",
"path": "bookingSlots",
"label": "Booking slots",
"defaultValue": [
{
"start": "2026-02-13T09:00:00",
"end": "2026-02-13T11:00:00"
},
{
"start": "2026-02-13T13:00:00",
"end": "2026-02-13T15:00:00"
},
{
"start": "2026-02-16T14:00:00",
"end": "2026-02-18T09:30:00"
}
],
"props": {
"minuteStep": 30,
"disabledRanges": [
{
"start": "2026-02-17T13:00:00",
"end": "2026-02-17T14:00:00"
}
],
"dayCountAriaLabel": "Number of slots taken: {count}",
"disabledDayCountAriaLabel": "Number of blocked slots: {count}"
}
}
]
}

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 and the two time pickers. 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 loads all four pieces, the day span and the start and end times, as the working selection; day or time re-picks reshape it without the add flow’s auto-commit, until the pill’s check icon confirms. Leaving the widget with a complete, changed selection also commits it. Confirming with a half re-picked selection surfaces incompleteMessage. 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.

range-datetime-calendar.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.rangeDateTimeCalendar('editableSessions', {
allowEdit: true,
minuteStep: 30,
label: 'Sessions',
defaultValue: [
{
start: '2026-09-07T09:00:00',
end: '2026-09-07T11:00:00',
},
{
start: '2026-09-08T14:00:00',
end: '2026-09-09T09:30:00',
},
],
}),
];
range-datetime-calendar.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "rangeDateTimeCalendar",
"path": "editableSessions",
"label": "Sessions",
"defaultValue": [
{
"start": "2026-09-07T09:00:00",
"end": "2026-09-07T11:00:00"
},
{
"start": "2026-09-08T14:00:00",
"end": "2026-09-09T09:30:00"
}
],
"props": {
"allowEdit": true,
"minuteStep": 30
}
}
]
}

Range Date Time Calendars can be styled as explained in the Styling Guide. They inherit the day grid and range highlighting styles of the Range Calendar along with the time-list variables of the embedded pickers.

Following you will find a list with the CSS Variables and a quick description of what you will style.

CSS VariableDescription
--gui-radius-mdCalendar container base radius
--gui-radius-rangeBorder radius applied to the start and end of a selected range (calculated as double radius-md)
--gui-bg-defaultCalendar and time list container background color
--gui-border-defaultDefault border color and cell hover border color
--gui-space-3Internal padding
--gui-calendar-change-month-button-widthWidth of the next/prev buttons
--gui-calendar-change-month-button-heightHeight of the next/prev buttons
--gui-text-defaultDefault text and focus border color
--gui-text-secondaryDay button hover background color
--gui-intent-primary-active”Today” border highlight color
--gui-intent-primarySelected range, selected day and selected time slot background color
--gui-bg-disabledDisabled day and disabled time slot background color
--gui-time-list-heightMaximum height of each embedded time list viewport
--gui-time-list-item-heightHeight of each time slot row
--gui-time-list-columnsNumber of columns in the time slot grid
--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 Time Calendar Widget in case you want to use your CSS styles.

range-datetime-calendar-anatomy.html
<gui-range-date-time-calendar-input class="gui-range-date-time-calendar gui-field">
<gui-range-date-time-calendar allow-edit="" class="gui-field">
<label class="gui-label" for="fieldUid" id="fieldUid_calendar_label"><span class="gui-label__text">Sessions</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--end-shadow gui-pills--start-shadow">
<div class="gui-pills__strip" role="toolbar" tabindex="-1" aria-label="Selected date-time 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:00 AM - 09/07/2026, 11:00 AM"
aria-description="Edit range 09/07/2026, 09:00 AM - 09/07/2026, 11:00 AM. Remove date"
>
<span class="gui-pills__pill-text">09/07/2026, 09:00 AM - 09/07/2026, 11:00 AM</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/08/2026, 02:00 PM - 09/09/2026, 09:30 AM"
aria-description="Edit range 09/08/2026, 02:00 PM - 09/09/2026, 09:30 AM. Remove date"
>
<span class="gui-pills__pill-text">09/08/2026, 02:00 PM - 09/09/2026, 09:30 AM</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-range-date-time-calendar__time-row">
<div class="gui-range-date-time-calendar__time-column">
<gui-time-picker class="gui-time-picker gui-field gui-range-date-time-calendar__start">
<span class="gui-label" id="fieldUid-start-time_label"><span class="gui-label__text">Start time</span></span>
<div class="gui-widget">
<gui-time id="time-input" class="gui-field" readonly="">
<div class="gui-widget">
<div
role="group"
id="fieldUid-start-time"
class="gui-widget-input gui-parts gui-parts-ring gui-time-input"
aria-labelledby="fieldUid-start-time_label"
aria-readonly="true"
>
<div dir="ltr" class="gui-parts__time-cluster gui-time-input__time-cluster">
<div class="gui-parts__touch-target gui-time-input__touch-target">
<input
type="text"
inputmode="numeric"
role="spinbutton"
autocomplete="off"
class="gui-parts__part gui-time-input__part"
data-type="hour"
maxlength="2"
placeholder="hh"
tabindex="0"
aria-label="Hour"
aria-valuemin="1"
aria-valuemax="12"
readonly=""
/>
<div class="gui-parts__visual-underline gui-time-input__visual-underline"></div>
</div>
<span class="gui-time-input__separator">:</span>
<div class="gui-parts__touch-target gui-time-input__touch-target">
<input
type="text"
inputmode="numeric"
role="spinbutton"
autocomplete="off"
class="gui-parts__part gui-time-input__part"
data-type="minute"
maxlength="2"
placeholder="mm"
tabindex="-1"
aria-label="Minute"
aria-valuemin="0"
aria-valuemax="59"
readonly=""
/>
<div class="gui-parts__visual-underline gui-time-input__visual-underline"></div>
</div>
</div>
<span class="gui-time-input__separator"></span>
<div class="gui-parts__touch-target gui-time-input__touch-target">
<button
type="button"
class="gui-parts__part gui-parts__dayperiod gui-time-input__part gui-time-input__dayperiod"
data-type="dayPeriod"
tabindex="-1"
aria-label="AM/PM"
>
AM
</button>
<div class="gui-parts__visual-underline gui-time-input__visual-underline"></div>
</div>
</div>
</div>
</gui-time>
<button
type="button"
class="gui-time-picker__arrow"
aria-haspopup="dialog"
aria-label="Show time list"
aria-expanded="false"
aria-controls="fieldUid-start-time_popup"
>
<span class="gui-caret" aria-hidden="true"></span>
</button>
<div class="gui-picker__panel" hidden="">
<gui-time-list role="dialog" id="fieldUid-start-time_popup" aria-label="Start time" hidden="">
<div
class="gui-time-list__viewport gui-time-list__viewport--grid"
role="grid"
style="--gui-time-list-height: 300px; --gui-time-list-item-height: 40px; --gui-time-list-columns: 4"
aria-label="Start time"
>
<div role="row" class="gui-time-list__row">
<button
type="button"
role="gridcell"
class="gui-time-list__option"
tabindex="0"
data-value="00:00:00"
aria-selected="false"
aria-disabled="false"
>
12:00 AM
</button>
<button
type="button"
role="gridcell"
class="gui-time-list__option"
tabindex="-1"
data-value="00:30:00"
aria-selected="false"
aria-disabled="false"
>
12:30 AM
</button>
<!-- More button.gui-time-list__option -->
</div>
<div role="row" class="gui-time-list__row">
<button
type="button"
role="gridcell"
class="gui-time-list__option"
tabindex="-1"
data-value="02:00:00"
aria-selected="false"
aria-disabled="false"
>
02:00 AM
</button>
<button
type="button"
role="gridcell"
class="gui-time-list__option"
tabindex="-1"
data-value="02:30:00"
aria-selected="false"
aria-disabled="false"
>
02:30 AM
</button>
<!-- More button.gui-time-list__option -->
</div>
<!-- More div.gui-time-list__row -->
</div>
</gui-time-list>
</div>
</div>
</gui-time-picker>
</div>
<div class="gui-range-date-time-calendar__time-column">
<gui-time-picker class="gui-time-picker gui-field gui-range-date-time-calendar__end">
<span class="gui-label" id="fieldUid-end-time_label"><span class="gui-label__text">End time</span></span>
<div class="gui-widget">
<gui-time id="time-input" class="gui-field" readonly="">
<div class="gui-widget">
<div
role="group"
id="fieldUid-end-time"
class="gui-widget-input gui-parts gui-parts-ring gui-time-input"
aria-labelledby="fieldUid-end-time_label"
aria-readonly="true"
>
<div dir="ltr" class="gui-parts__time-cluster gui-time-input__time-cluster">
<div class="gui-parts__touch-target gui-time-input__touch-target">
<input
type="text"
inputmode="numeric"
role="spinbutton"
autocomplete="off"
class="gui-parts__part gui-time-input__part"
data-type="hour"
maxlength="2"
placeholder="hh"
tabindex="0"
aria-label="Hour"
aria-valuemin="1"
aria-valuemax="12"
readonly=""
/>
<div class="gui-parts__visual-underline gui-time-input__visual-underline"></div>
</div>
<span class="gui-time-input__separator">:</span>
<div class="gui-parts__touch-target gui-time-input__touch-target">
<input
type="text"
inputmode="numeric"
role="spinbutton"
autocomplete="off"
class="gui-parts__part gui-time-input__part"
data-type="minute"
maxlength="2"
placeholder="mm"
tabindex="-1"
aria-label="Minute"
aria-valuemin="0"
aria-valuemax="59"
readonly=""
/>
<div class="gui-parts__visual-underline gui-time-input__visual-underline"></div>
</div>
</div>
<span class="gui-time-input__separator"></span>
<div class="gui-parts__touch-target gui-time-input__touch-target">
<button
type="button"
class="gui-parts__part gui-parts__dayperiod gui-time-input__part gui-time-input__dayperiod"
data-type="dayPeriod"
tabindex="-1"
aria-label="AM/PM"
>
AM
</button>
<div class="gui-parts__visual-underline gui-time-input__visual-underline"></div>
</div>
</div>
</div>
</gui-time>
<button
type="button"
class="gui-time-picker__arrow"
aria-haspopup="dialog"
aria-label="Show time list"
aria-expanded="false"
aria-controls="fieldUid-end-time_popup"
>
<span class="gui-caret" aria-hidden="true"></span>
</button>
<div class="gui-picker__panel" hidden="">
<gui-time-list role="dialog" id="fieldUid-end-time_popup" aria-label="End time" hidden="">
<div
class="gui-time-list__viewport gui-time-list__viewport--grid"
role="grid"
style="--gui-time-list-height: 300px; --gui-time-list-item-height: 40px; --gui-time-list-columns: 4"
aria-label="End time"
>
<div role="row" class="gui-time-list__row">
<button
type="button"
role="gridcell"
class="gui-time-list__option"
tabindex="0"
data-value="00:00:00"
aria-selected="false"
aria-disabled="false"
>
12:00 AM
</button>
<button
type="button"
role="gridcell"
class="gui-time-list__option"
tabindex="-1"
data-value="00:30:00"
aria-selected="false"
aria-disabled="false"
>
12:30 AM
</button>
<!-- More button.gui-time-list__option -->
</div>
<div role="row" class="gui-time-list__row">
<button
type="button"
role="gridcell"
class="gui-time-list__option"
tabindex="-1"
data-value="02:00:00"
aria-selected="false"
aria-disabled="false"
>
02:00 AM
</button>
<button
type="button"
role="gridcell"
class="gui-time-list__option"
tabindex="-1"
data-value="02:30:00"
aria-selected="false"
aria-disabled="false"
>
02:30 AM
</button>
<!-- More button.gui-time-list__option -->
</div>
<!-- More div.gui-time-list__row -->
</div>
</gui-time-list>
</div>
</div>
</gui-time-picker>
</div>
</div>
<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>
<!-- 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>
<!-- 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-date-time-calendar>
</gui-range-date-time-calendar-input>