Skip to content
Components, switch product

Time input

<gui-time> is a time field typed part by part: the hour, the minute and, on a 12-hour clock, AM or PM. Its value is an ISO time, such as 18:45:00. To pick the time from a list too, use the Time picker.

Code of the example above
TimeBasic.tsx
import { GuiTime } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function TimeBasic() {
return <GuiTime label="Alarm" />;
}

The element’s entry point is @golemui/gui-components/time-input, which registers <gui-time> and nothing else. To install the package and load the stylesheet, see Installation.

The @golemui/gui-components/react components have typed props and an on* prop for each event. React 18 or later.

AlarmField.tsx
import { useState } from 'react';
import { GuiTime } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function AlarmField() {
const [alarm, setAlarm] = useState('');
return (
<GuiTime
label="Alarm"
name="alarm"
value={alarm}
onGuiChange={(event) => setAlarm(event.detail.value ?? '')}
/>
);
}

Properties

Property Type Default Description
localeId attribute locale-id string – BCP 47 locale for formatting and parsing, such as en-US or es.
showErrors attribute show-errors boolean true Whether the element renders its own error list. Elements that embed it turn it off and show the errors themselves.
showHint attribute show-hint boolean true Whether the element renders its hint. Elements that embed it turn it off and show the hint themselves: aria-describedby still points at the hint by its id.
icon string '' Icon class name shown inside the control, for example from an icon font.
hourAriaLabel attribute hour-aria-label string – Accessible name of the hour part. An empty value keeps the default.
minuteAriaLabel attribute minute-aria-label string – Accessible name of the minute part. An empty value keeps the default.
dayPeriodAriaLabel attribute day-period-aria-label string – Accessible name of the AM/PM part. An empty value keeps the default.
value string – The time, as an ISO time (HH:mm:ss).
hourFormat attribute hour-format HourFormat – 12- or 24-hour clock. Defaults to the locale's.
minuteStep attribute minute-step number 1 Minutes between the times offered in the list.
minTime attribute min-time string – Earliest selectable time, as an ISO time (HH:mm:ss).
maxTime attribute max-time string – Latest selectable time, as an ISO time (HH:mm:ss).
minTimeMessage attribute min-time-message string – Error for a time before minTime.
maxTimeMessage attribute max-time-message string – Error for a time after maxTime.
incompleteMessage attribute incomplete-message string – Error when focus leaves a partly filled value.
uid string – The id of the element's control. The ids of its label, hint and errors derive from it. Optional: when it is not set, the element generates one from its tag name and a page-wide counter, e.g. gui-textinput-3. Generated ids depend on creation order, so a server-rendered element must set uid or its ids will not match after hydration.

Form control properties

Every field has these, from the base class of the form controls.

Property Type Default Description
name string – The name the value is submitted under. Without it the element stays out of its form. Reflected, like a native control's: the form reads a single value's name from the attribute.
label string – The visible label, which also names the control for assistive technology. Without one the control has no accessible name; the date, time, range, tags and file fields warn about it in development builds.
hint string – Help text shown under the label and announced as the control's description.
errors string[] [] Error messages to show, typically from your own validation. They show as soon as they are set, unless touched is false.
touched boolean – Whether the user has interacted with the control. Leave it unset unless you validate on interaction: false holds errors back until it becomes true.
required boolean false The control needs a value: it is marked as required and, with a name, blocks submission.
readOnly attribute readonly boolean – The value can be read and focused but not changed.
disabled boolean – Disabled by its own attribute or by a disabled <fieldset> around it. Setting the property sets the attribute, like a native control's.
form read-only, no attribute HTMLFormElement | null – The <form> the element belongs to, if any.
validity read-only, no attribute ValidityState – The element's validity, like a native control's.
validationMessage read-only, no attribute string – The message the browser shows for an invalid value.

Methods

Method Description
checkValidity(): boolean –
reportValidity(): boolean –

Events

Every event bubbles and is composed, so you can listen on any ancestor.

Event Description
gui-input The user changed the value. detail.value is the new value.
gui-change The user committed the value. detail.value is the committed value.
gui-blur Focus left the control.
gui-focus One of the parts of the field received focus.
gui-input-error The element rejected what the user entered, such as an impossible date or a value out of bounds. detail.message is the error; show it through errors.
gui-parts-change The typed parts changed before they form a complete value, for a host that mirrors them.

value takes an ISO time, HH:mm:ss or HH:mm, on a 24-hour clock whatever the field shows. A typed time always has 00 seconds. The element fires gui-input and then gui-change as soon as the hour and the minute are both filled, with the time in event.detail.value. When the user clears a part, the value becomes empty and both events fire with null.

Value: 09:15:00

Code of the example above
TimeValue.tsx
import { useState } from 'react';
import { GuiTime } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function TimeValue() {
const [value, setValue] = useState<string | undefined>('09:15:00');
return (
<>
<GuiTime
id="time-standup"
label="Stand-up"
value={value}
onGuiChange={(event) => setValue(event.detail.value)}
/>
<p role="status">Value: {value}</p>
</>
);
}

locale-id takes a BCP 47 locale, such as en-US or de-DE. It sets the clock, the separators and the AM/PM labels. hour-format, 12 or 24, sets the clock whatever the locale. Without either, the field uses a 12-hour clock with AM and PM, as in English.

Code of the example above
TimeClock.tsx
import { GuiTime } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function TimeClock() {
return (
<div className="gui-grid gui-grid--row">
<div className="gui-grid__cell">
<GuiTime label="United States" localeId="en-US" value="18:45:00" />
</div>
<div className="gui-grid__cell">
<GuiTime label="Germany" localeId="de-DE" value="18:45:00" />
</div>
<div className="gui-grid__cell">
<GuiTime
label="24-hour clock"
localeId="en-US"
hourFormat="24"
value="18:45:00"
/>
</div>
</div>
);
}

On a 12-hour clock the AM/PM part is a toggle. It starts on AM, and the value only changes when the hour and the minute are filled.

minute-step sets how many minutes the arrow keys add or take from the minute part, which wraps from 59 to 0. The user can still type any minute.

Code of the example above
TimeStep.tsx
import { GuiTime } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function TimeStep() {
return (
<GuiTime
label="Reminder"
hint="The arrow keys move the minutes in steps of 15."
minuteStep={15}
value="09:00:00"
/>
);
}

min-time and max-time take ISO times and are inclusive. A time outside them is still entered: the element keeps it as its value, marks it as out of bounds for its form and fires gui-input-error with the reason. Show it with errors, as below: the gui-input-error listener shows the message, and the next gui-input clears it.

Code of the example above
TimeBounds.tsx
import { useState } from 'react';
import { GuiTime } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function TimeBounds() {
const [errors, setErrors] = useState<string[]>([]);
return (
<GuiTime
id="time-call"
label="Call me at"
hint="Between 9:00 AM and 5:30 PM."
minTime="09:00:00"
maxTime="17:30:00"
errors={errors}
// The element reports what it rejects; show it with errors.
onGuiInputError={(event) => setErrors([event.detail.message])}
onGuiInput={() => setErrors([])}
/>
);
}

gui-input-error also fires when focus leaves a field with only the hour or the minute filled; the value becomes empty. Replace the English messages with min-time-message, max-time-message and incomplete-message, or translate them for every element as in i18n.

disabled, readonly and icon work as on the Date input.

With a name, <gui-time> submits its ISO time under that name, such as opensAt=08:30:00, and nothing while it is empty. required, and a time before min-time or after max-time, block a submit; the browser shows the element’s message for the time. Submit the empty field, then try 1:00 PM.

Code of the example above
TimeNativeForm.tsx
import { useState } from 'react';
import { GuiButton, GuiTime } from '@golemui/gui-components/react';
import '@golemui/gui-components/index.css';
export function TimeNativeForm() {
const [result, setResult] = useState('');
return (
<form
id="time-form"
onSubmit={(event) => {
event.preventDefault();
const data = Object.fromEntries(new FormData(event.currentTarget));
setResult(`Submitted ${JSON.stringify(data)}`);
}}
>
<div className="gui-grid gui-grid--row">
<div className="gui-grid__cell gui-grid__cell--span-3">
<GuiTime
label="Opening time"
name="opensAt"
minTime="06:00:00"
maxTime="12:00:00"
maxTimeMessage="Open by noon at the latest."
required
/>
</div>
<div className="gui-grid__cell">
<GuiButton type="submit" label="Save" />
</div>
</div>
<p role="status">{result}</p>
</form>
);
}

How the elements submit, validate and reset is in Native forms.

<gui-time> renders into the light DOM, so you can style every part with plain CSS. These are the parts and their public classes, here on a 12-hour clock:

gui-time
<gui-time class="gui-field">
<span class="gui-label" id="alarm_label">
<span class="gui-label__text">Alarm</span>
</span>
<div class="gui-widget">
<div
role="group"
id="alarm"
class="gui-widget-input gui-parts gui-parts-ring gui-time-input"
aria-labelledby="alarm_label"
>
<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"
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"
aria-valuenow="7"
/>
<div
class="gui-parts__visual-underline gui-time-input__visual-underline"
></div>
</div>
<span class="gui-time-input__separator">:</span>
<!-- The minute part, like the hour, with tabindex="-1" -->
</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>
ClassPart
gui-fieldThe element itself. Lines its parts up with the fields next to it in a gui-grid row.
gui-label, gui-label__text, gui-widget-hintThe label, its text with the required marker, and the hint.
gui-widgetThe box around the control.
gui-widget-input, gui-parts, gui-time-inputThe group of parts, the part that looks like a field.
gui-parts-ringThe same group: draws the focus ring and the error border around all the parts.
gui-parts__time-cluster, gui-time-input__time-clusterThe hour and minute, kept left to right in a right-to-left page.
gui-parts__touch-target, gui-time-input__touch-targetThe box around one part, its touch target.
gui-parts__part, gui-time-input__partOne part, with its data-type: an <input> for hour and minute.
gui-parts__dayperiod, gui-time-input__dayperiodThe AM/PM toggle, a <button>.
gui-parts__visual-underlineThe line under the focused part.
gui-time-input__separatorA separator between parts, from the locale.
gui-calendar--icon, gui-widget-iconOn the group when there is an icon, and the icon itself.
gui-validator, gui-validator__errorThe errors container, there while there are errors, and one message.

The ids derive from uid, or from a generated id such as gui-time-3 when you don’t set one. Select by class or by tag, not by id.

The field reads the same design tokens as the Date input: --gui-widget-size for its height, --gui-bg-surface, --gui-border-default and --gui-radius-md for its box, --gui-border-focus and --gui-shadow-focus while a part is focused, and --gui-intent-error with errors. The parts and the AM/PM toggle use --gui-text-default and the browser’s monospace font.

styles.css
/* A brand focus color on every time field. */
gui-time {
--gui-border-focus: #d96c3f;
}

To restyle beyond the tokens, see Overriding styles; for dark mode and the Clay theme, see Themes and dark mode.

  • Name. The parts sit in a group that the label names. Without a label the group has no name, and development builds log a warning.
  • Parts. The hour and minute are spin buttons named Hour and Minute, with their range and current number. The AM/PM toggle is a button named AM/PM. Rename them with hour-aria-label, minute-aria-label and day-period-aria-label, or translate them for every element under the keys hour, minute and dayPeriod.
  • One tab stop. Only the first part is in the tab order. The arrow keys move between the parts.
  • Direction. In a right-to-left page the hour and minute keep their left-to-right order.
  • Description and errors. The hint describes the group, and errors mark it with aria-invalid and aria-errormessage, as on the Date input.
KeyAction
TabMoves focus to the first part, and out of the field.
0 to 9Type the hour or the minute. A full part moves focus to the next part that is still empty.
↑ / ↓Add or subtract one hour, or minute-step minutes. On the AM/PM toggle, switch it.
SpaceOn the AM/PM toggle, switches it.
← / →Move to the part on the left or right, in the order you see them.
Backspace / DeleteDelete digits. Leaving a part empty clears the value.

What every element shares, such as translating the browser messages, is in Accessibility.