Skip to content

Time Picker

Time Picker widgets are Input Fields that let the user pick a time from a drop-down list of slots. The slots are generated from minTime to maxTime (inclusive) stepping minuteStep minutes, with their labels localized to the user’s 12-hour or 24-hour convention. By default the field is read-only and values come only from the list; set allowCustomTime to also let the user type a time. The list closes with the Esc key.

The widget emits an ISO time string (HH:mm:ss) on change — pair it with the { format: 'time' } validator.

timepicker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.timePicker('meetingTime', {
label: 'Meeting Time',
}),
];
timepicker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "timePicker",
"path": "meetingTime",
"label": "Meeting Time"
}
]
}

Use these props to customize your Time Picker widget.

proptypedescription
allowCustomTimebooleanAllows typing a time in the input; when false (default) values come only from the list
disabledRangeMessagestring | LocalizableError message shown when a typed time falls inside a disabled range
disabledRangesarray{ start, end } ISO time ranges (both ends inclusive) whose slots render disabled
heightnumberTotal height of the drop-down list viewport. Defaults to 300
hintstringA description to display below the input
hourFormat'12' | '24'Forces 12-hour or 24-hour slot labels and typing mode; when omitted the locale decides
iconstringA css class to display an icon inside the input
itemHeightnumberFixed height of each slot row. Defaults to 40
maxTimestringLast selectable slot (ISO time, inclusive). Defaults to 23:59:59
maxTimeMessagestring | LocalizableError message shown when a typed time is after maxTime
minTimestringFirst selectable slot (ISO time, inclusive). Defaults to 00:00:00
minTimeMessagestring | LocalizableError message shown when a typed time is before minTime
minuteStepnumberMinutes between generated slots, also the arrow-key minute increment when typing. Defaults to 30
noAvailableTimesMessagestring | LocalizableShown in the list when the bounds yield no slots. Defaults to No available times

Use the property hint to add a description or validation instructions.

timepicker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.timePicker('meetingTime', {
hint: 'Please pick the meeting start time',
label: 'Meeting Time',
}),
];
timepicker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "timePicker",
"path": "meetingTime",
"label": "Meeting Time",
"props": {
"hint": "Please pick the meeting start time"
}
}
]
}

Use the property icon to add an icon, which appears next to the toggle chevron. The value of icon represents a set of CSS classes separated by spaces.

timepicker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.timePicker('meetingTime', {
icon: 'schedule',
label: 'Meeting Time',
}),
];
timepicker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "timePicker",
"path": "meetingTime",
"label": "Meeting Time",
"props": {
"icon": "schedule"
}
}
]
}

By default the 12-hour/24-hour convention comes from the locale’s hour cycle and drives both the slot labels (e.g. 9:30 AM vs 09:30) and the typing mode. Use the property hourFormat ('12' or '24') to force one of them.

timepicker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.timePicker('meetingTime12', {
hourFormat: '12',
label: 'Meeting Time (12h)',
}),
gui.inputs.timePicker('meetingTime24', {
hourFormat: '24',
label: 'Meeting Time (24h)',
}),
];
timepicker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "timePicker",
"path": "meetingTime12",
"label": "Meeting Time (12h)",
"props": {
"hourFormat": "12"
}
},
{
"kind": "input",
"type": "timePicker",
"path": "meetingTime24",
"label": "Meeting Time (24h)",
"props": {
"hourFormat": "24"
}
}
]
}

Use minTime, maxTime and minuteStep to control which slots are generated, and disabledRanges to grey out slots inside { start, end } ranges (both ends inclusive). Disabled slots are skipped by keyboard navigation and cannot be selected.

timepicker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.timePicker('meetingTime', {
hint: '30m slots from 9:00 to 18:00, lunch break disabled',
minTime: '09:00:00',
maxTime: '18:00:00',
minuteStep: 30,
disabledRanges: [
{
start: '13:00:00',
end: '14:00:00',
},
],
label: 'Pick a time slot',
}),
];
timepicker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "timePicker",
"path": "meetingTime",
"label": "Pick a time slot",
"props": {
"hint": "30m slots from 9:00 to 18:00, lunch break disabled",
"minTime": "09:00:00",
"maxTime": "18:00:00",
"minuteStep": 30,
"disabledRanges": [
{
"start": "13:00:00",
"end": "14:00:00"
}
]
}
}
]
}

Use height to set the drop-down list viewport height (default 300) and itemHeight to set the height of each slot row (default 40). Both are in pixels; the list scrolls when the slots exceed the viewport.

timepicker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.timePicker('meetingTime', {
hint: 'A shorter 200px viewport with taller 56px rows',
minTime: '09:00:00',
maxTime: '18:00:00',
minuteStep: 30,
height: 200,
itemHeight: 56,
label: 'Meeting Time',
}),
];
timepicker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "timePicker",
"path": "meetingTime",
"label": "Meeting Time",
"props": {
"hint": "A shorter 200px viewport with taller 56px rows",
"minTime": "09:00:00",
"maxTime": "18:00:00",
"minuteStep": 30,
"height": 200,
"itemHeight": 56
}
}
]
}

Use the property allowCustomTime to let the user type any time directly in the input, in addition to picking a slot. Typed times are still validated against minTime, maxTime and disabledRanges: a violation raises an input error whose message you can customize (and localize) with minTimeMessage, maxTimeMessage and disabledRangeMessage.

timepicker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.timePicker('meetingTime', {
hint: 'Type any time between 9:00 and 18:00 or pick a slot',
allowCustomTime: true,
minTime: '09:00:00',
maxTime: '18:00:00',
disabledRanges: [
{
start: '13:00:00',
end: '14:00:00',
},
],
minTimeMessage: 'Office not open until 9:00',
maxTimeMessage: 'Office closed from 18:00',
disabledRangeMessage: 'Lunch break is not available',
label: 'Meeting Time',
}),
];
timepicker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "timePicker",
"path": "meetingTime",
"label": "Meeting Time",
"props": {
"hint": "Type any time between 9:00 and 18:00 or pick a slot",
"allowCustomTime": true,
"minTime": "09:00:00",
"maxTime": "18:00:00",
"disabledRanges": [
{
"start": "13:00:00",
"end": "14:00:00"
}
],
"minTimeMessage": "Office not open until 9:00",
"maxTimeMessage": "Office closed from 18:00",
"disabledRangeMessage": "Lunch break is not available"
}
}
]
}

When minTime and maxTime generate no slots, the drop-down list shows an empty-state message. Use noAvailableTimesMessage to customize (and localize) it (it defaults to No available times).

timepicker.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.inputs.timePicker('meetingTime', {
hint: 'These bounds generate no slots, so the list shows the empty-state message',
minTime: '18:00:00',
maxTime: '09:00:00',
noAvailableTimesMessage: 'No slots available',
label: 'Meeting Time',
}),
];
timepicker.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "input",
"type": "timePicker",
"path": "meetingTime",
"label": "Meeting Time",
"props": {
"hint": "These bounds generate no slots, so the list shows the empty-state message",
"minTime": "18:00:00",
"maxTime": "09:00:00",
"noAvailableTimesMessage": "No slots available"
}
}
]
}

Time Pickers can be styled as explained in the Styling Guide. The typed field and the slot list each have their own styling variables.

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

CSS VariableDescription
--gui-text-defaultInput and slot text color, active piece (hour/minute) underline
--gui-intent-errorInput border color when invalid
--gui-border-focusInput border and focused slot outline color
--gui-bg-defaultBackground color for the drop-down list container
--gui-border-defaultBorder color for the drop-down list container
--gui-radius-mdBorder radius for the drop-down list container
--gui-intent-primaryBackground color for the selected slot
--gui-intent-primary-hoverBackground color for slots on hover
--gui-intent-primary-textText color for the selected and hovered slots
--gui-bg-disabledBackground color for disabled slots
--gui-text-mutedText color of the “no available times” message

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

timepicker-anatomy.html
<gui-time-picker class="gui-time-picker gui-field">
<label class="gui-label" for="fieldUid" id="fieldUid_label">
Label
<div class="gui-widget-hint" id="fieldUid_hint">Hint</div>
</label>
<div role="button" tabindex="-1" class="gui-widget" aria-expanded="false">
<!-- The typing surface is a Time Input; readonly unless allowCustomTime -->
<gui-time id="time-input" class="gui-calendar--icon">
<div class="gui-widget">
<div class="gui-widget-input gui-time-input" role="group">
<div class="gui-time-input__touch-target">
<input type="text" inputmode="numeric" class="gui-time-input__part" data-type="hour" maxlength="2" placeholder="hh" tabindex="0" value="09">
<div class="gui-time-input__visual-underline"></div>
</div>
<span class="gui-time-input__separator">:</span>
<div class="gui-time-input__touch-target">
<input type="text" inputmode="numeric" class="gui-time-input__part" data-type="minute" maxlength="2" placeholder="mm" tabindex="-1" value="30">
<div class="gui-time-input__visual-underline"></div>
</div>
<!-- Only rendered in 12-hour mode, at the locale's position -->
<div class="gui-time-input__touch-target">
<button type="button" class="gui-time-input__part gui-time-input__dayperiod" data-type="dayPeriod" tabindex="-1" aria-label="AM/PM">AM</button>
<div class="gui-time-input__visual-underline"></div>
</div>
</div>
<span class="gui-widget-icon schedule" data-icon="schedule"></span>
</div>
</gui-time>
<span class="gui-time-picker__arrow">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 256 256"><path d="..."></path></svg>
</span>
<!-- Drop-down list of time slots -->
<gui-time-list>
<div class="gui-time-list__viewport" role="listbox" style="--gui-time-list-height: 300px; --gui-time-list-item-height: 40px; --gui-time-list-columns: 1;">
<button type="button" role="option" class="gui-time-list__option gui-time-list__option--selected" tabindex="0" data-value="09:30:00" aria-selected="true" aria-disabled="false">9:30 AM</button>
<button type="button" role="option" class="gui-time-list__option" tabindex="-1" data-value="10:00:00" aria-selected="false" aria-disabled="true" disabled>10:00 AM</button>
</div>
<!-- When minTime/maxTime yield no slots, the viewport is replaced by: -->
<!-- <div class="gui-time-list__empty">No available times</div> -->
</gui-time-list>
</div>
</gui-time-picker>