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.
import { GuiTime } from '@golemui/gui-components/react';import '@golemui/gui-components/index.css';
export function TimeBasic() { return <GuiTime label="Alarm" />;}import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';import '@golemui/gui-components/time-input';
@Component({ selector: 'app-time-basic', schemas: [CUSTOM_ELEMENTS_SCHEMA], template: `<gui-time label="Alarm"></gui-time>`,})export class TimeBasicComponent {}<script setup lang="ts">import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';</script>
<template> <gui-time label="Alarm"></gui-time></template>import { LitElement, html } from 'lit';import { customElement } from 'lit/decorators.js';import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
@customElement('time-basic')export class TimeBasic extends LitElement { protected override createRenderRoot() { return this; }
override render() { return html`<gui-time label="Alarm"></gui-time>`; }}<gui-time label="Alarm"></gui-time>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.
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 ?? '')} /> );}Add CUSTOM_ELEMENTS_SCHEMA to the component that uses the tags, and the stylesheet to styles in angular.json.
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';import type { GuiEventMap, GuiTimeEvents } from '@golemui/gui-components';import '@golemui/gui-components/time-input';
type ChangeEvent = GuiEventMap<typeof GuiTimeEvents>['gui-change'];
@Component({ selector: 'app-alarm-field', schemas: [CUSTOM_ELEMENTS_SCHEMA], template: ` <gui-time label="Alarm" name="alarm" [value]="alarm" (gui-change)="onChange($event)" ></gui-time> `,})export class AlarmFieldComponent { alarm = '';
onChange(event: Event) { this.alarm = (event as ChangeEvent).detail.value ?? ''; }}"styles": ["node_modules/@golemui/gui-components/lib/styles/index.css"]Tell Vue's compiler that gui-* tags are custom elements, and add the typings once for typed props and @gui-* handlers.
<script setup lang="ts">import { ref } from 'vue';import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
const alarm = ref('');</script>
<template> <gui-time label="Alarm" name="alarm" :value="alarm" @gui-change="alarm = $event.detail.value ?? ''" /></template>vue({ template: { compilerOptions: { isCustomElement: (tag) => tag.startsWith('gui-') } },});import type {} from '@golemui/gui-components/vue';The page's stylesheet styles the gui-* elements, so it only reaches them outside a shadow root. Render the host component into the light DOM too, as below, or load the stylesheet into its shadow root.
import { LitElement, html } from 'lit';import { customElement, state } from 'lit/decorators.js';import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
@customElement('alarm-field')export class AlarmField extends LitElement { @state() private alarm = '';
protected override createRenderRoot() { return this; }
override render() { return html` <gui-time label="Alarm" name="alarm" .value=${this.alarm} @gui-change=${(event: CustomEvent) => (this.alarm = event.detail.value)} ></gui-time> `; }}With any bundler, such as Vite. Import the element once, anywhere, and use the tag in your markup.
<gui-time label="Alarm" name="alarm"></gui-time>
<script type="module" src="./main.js"></script>import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
const element = document.querySelector('gui-time');
element.addEventListener('gui-change', (event) => { console.log(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. |
Examples
Section titled “Examples”Value and events
Section titled “Value and events”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
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> </> );}import { Component, CUSTOM_ELEMENTS_SCHEMA, signal } from '@angular/core';import type { GuiEventMap, GuiTimeEvents } from '@golemui/gui-components';import '@golemui/gui-components/time-input';
type TimeEvent<K extends keyof typeof GuiTimeEvents> = GuiEventMap< typeof GuiTimeEvents>[K];
@Component({ selector: 'app-time-value', schemas: [CUSTOM_ELEMENTS_SCHEMA], template: ` <gui-time id="time-standup" label="Stand-up" [value]="value()" (gui-change)="onChange($event)" ></gui-time> <p id="time-standup-value" role="status">Value: {{ value() }}</p> `,})export class TimeValueComponent { value = signal<string | undefined>('09:15:00');
onChange(event: Event) { this.value.set((event as TimeEvent<'gui-change'>).detail.value); }}<script setup lang="ts">import { ref } from 'vue';import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
const value = ref<string | undefined>('09:15:00');</script>
<template> <gui-time id="time-standup" label="Stand-up" :value="value" @gui-change="value = $event.detail.value" ></gui-time> <p id="time-standup-value" role="status">Value: {{ value }}</p></template>import { LitElement, html } from 'lit';import { customElement, state } from 'lit/decorators.js';import type { GuiEventMap, GuiTimeEvents } from '@golemui/gui-components';import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
type TimeEvent<K extends keyof typeof GuiTimeEvents> = GuiEventMap< typeof GuiTimeEvents>[K];
@customElement('time-value')export class TimeValue extends LitElement { @state() private value: string | undefined = '09:15:00';
protected override createRenderRoot() { return this; }
private onChange(event: TimeEvent<'gui-change'>) { this.value = event.detail.value; }
override render() { return html` <gui-time id="time-standup" label="Stand-up" .value=${this.value} @gui-change=${this.onChange} ></gui-time> <p role="status">Value: ${this.value}</p> `; }}<gui-time id="time-standup" label="Stand-up" value="09:15:00"></gui-time><p id="time-standup-value" role="status">Value: 09:15:00</p>
<script type="module"> const standup = document.querySelector('#time-standup');
standup.addEventListener('gui-change', (event) => { document.querySelector('#time-standup-value').textContent = `Value: ${event.detail.value}`; });</script>12 and 24-hour clock
Section titled “12 and 24-hour clock”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.
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> );}import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';import '@golemui/gui-components/time-input';
@Component({ selector: 'app-time-clock', schemas: [CUSTOM_ELEMENTS_SCHEMA], template: ` <div class="gui-grid gui-grid--row"> <div class="gui-grid__cell"> <gui-time label="United States" locale-id="en-US" value="18:45:00" ></gui-time> </div> <div class="gui-grid__cell"> <gui-time label="Germany" locale-id="de-DE" value="18:45:00"></gui-time> </div> <div class="gui-grid__cell"> <gui-time label="24-hour clock" locale-id="en-US" hour-format="24" value="18:45:00" ></gui-time> </div> </div> `,})export class TimeClockComponent {}<script setup lang="ts">import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';</script>
<template> <div class="gui-grid gui-grid--row"> <div class="gui-grid__cell"> <gui-time label="United States" locale-id="en-US" value="18:45:00" ></gui-time> </div> <div class="gui-grid__cell"> <gui-time label="Germany" locale-id="de-DE" value="18:45:00"></gui-time> </div> <div class="gui-grid__cell"> <gui-time label="24-hour clock" locale-id="en-US" hour-format="24" value="18:45:00" ></gui-time> </div> </div></template>import { LitElement, html } from 'lit';import { customElement } from 'lit/decorators.js';import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
@customElement('time-clock')export class TimeClock extends LitElement { protected override createRenderRoot() { return this; }
override render() { return html` <div class="gui-grid gui-grid--row"> <div class="gui-grid__cell"> <gui-time label="United States" locale-id="en-US" value="18:45:00" ></gui-time> </div> <div class="gui-grid__cell"> <gui-time label="Germany" locale-id="de-DE" value="18:45:00" ></gui-time> </div> <div class="gui-grid__cell"> <gui-time label="24-hour clock" locale-id="en-US" hour-format="24" value="18:45:00" ></gui-time> </div> </div> `; }}<div class="gui-grid gui-grid--row"> <div class="gui-grid__cell"> <gui-time label="United States" locale-id="en-US" value="18:45:00"></gui-time> </div> <div class="gui-grid__cell"> <gui-time label="Germany" locale-id="de-DE" value="18:45:00"></gui-time> </div> <div class="gui-grid__cell"> <gui-time label="24-hour clock" locale-id="en-US" hour-format="24" value="18:45:00"></gui-time> </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
Section titled “Minute step”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.
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" /> );}import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';import '@golemui/gui-components/time-input';
@Component({ selector: 'app-time-step', schemas: [CUSTOM_ELEMENTS_SCHEMA], template: ` <gui-time label="Reminder" hint="The arrow keys move the minutes in steps of 15." [minuteStep]="15" value="09:00:00" ></gui-time> `,})export class TimeStepComponent {}<script setup lang="ts">import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';</script>
<template> <gui-time label="Reminder" hint="The arrow keys move the minutes in steps of 15." :minute-step="15" value="09:00:00" ></gui-time></template>import { LitElement, html } from 'lit';import { customElement } from 'lit/decorators.js';import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
@customElement('time-step')export class TimeStep extends LitElement { protected override createRenderRoot() { return this; }
override render() { return html` <gui-time label="Reminder" hint="The arrow keys move the minutes in steps of 15." minute-step="15" value="09:00:00" ></gui-time> `; }}<gui-time label="Reminder" hint="The arrow keys move the minutes in steps of 15." minute-step="15" value="09:00:00"></gui-time>Bounds
Section titled “Bounds”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.
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([])} /> );}import { Component, CUSTOM_ELEMENTS_SCHEMA, signal } from '@angular/core';import type { GuiEventMap, GuiTimeEvents } from '@golemui/gui-components';import '@golemui/gui-components/time-input';
type TimeEvent<K extends keyof typeof GuiTimeEvents> = GuiEventMap< typeof GuiTimeEvents>[K];
@Component({ selector: 'app-time-bounds', schemas: [CUSTOM_ELEMENTS_SCHEMA], template: ` <gui-time id="time-call" label="Call me at" hint="Between 9:00 AM and 5:30 PM." min-time="09:00:00" max-time="17:30:00" [errors]="errors()" (gui-input-error)="onInputError($event)" (gui-input)="errors.set([])" ></gui-time> `,})export class TimeBoundsComponent { errors = signal<string[]>([]);
// The element reports what it rejects; show it with errors. onInputError(event: Event) { this.errors.set([(event as TimeEvent<'gui-input-error'>).detail.message]); }}<script setup lang="ts">import { ref } from 'vue';import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
const errors = ref<string[]>([]);</script>
<template> <!-- The element reports what it rejects; show it with errors. --> <gui-time id="time-call" label="Call me at" hint="Between 9:00 AM and 5:30 PM." min-time="09:00:00" max-time="17:30:00" :errors.prop="errors" @gui-input-error="errors = [$event.detail.message]" @gui-input="errors = []" ></gui-time></template>import { LitElement, html } from 'lit';import { customElement, state } from 'lit/decorators.js';import type { GuiEventMap, GuiTimeEvents } from '@golemui/gui-components';import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
type TimeEvent<K extends keyof typeof GuiTimeEvents> = GuiEventMap< typeof GuiTimeEvents>[K];
@customElement('time-bounds')export class TimeBounds extends LitElement { @state() private errors: string[] = [];
protected override createRenderRoot() { return this; }
// The element reports what it rejects; show it with errors. private onInputError(event: TimeEvent<'gui-input-error'>) { this.errors = [event.detail.message]; }
private onInput() { this.errors = []; }
override render() { return html` <gui-time id="time-call" label="Call me at" hint="Between 9:00 AM and 5:30 PM." min-time="09:00:00" max-time="17:30:00" .errors=${this.errors} @gui-input-error=${this.onInputError} @gui-input=${this.onInput} ></gui-time> `; }}<gui-time id="time-call" label="Call me at" hint="Between 9:00 AM and 5:30 PM." min-time="09:00:00" max-time="17:30:00"></gui-time>
<script type="module"> const call = document.querySelector('#time-call');
// The element reports what it rejects; show it with errors. call.addEventListener('gui-input-error', (event) => { call.errors = [event.detail.message]; }); call.addEventListener('gui-input', () => { call.errors = []; });</script>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.
In a form
Section titled “In a form”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.
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> );}import { Component, CUSTOM_ELEMENTS_SCHEMA, signal } from '@angular/core';import '@golemui/gui-components/button';import '@golemui/gui-components/time-input';
@Component({ selector: 'app-time-native-form', schemas: [CUSTOM_ELEMENTS_SCHEMA], template: ` <form id="time-form" #form (submit)="onSubmit($event, form)"> <div class="gui-grid gui-grid--row"> <div class="gui-grid__cell gui-grid__cell--span-3"> <gui-time label="Opening time" name="opensAt" min-time="06:00:00" max-time="12:00:00" max-time-message="Open by noon at the latest." required ></gui-time> </div> <div class="gui-grid__cell"> <gui-button type="submit" label="Save"></gui-button> </div> </div> <p id="time-form-result" role="status">{{ result() }}</p> </form> `,})export class TimeNativeFormComponent { result = signal('');
onSubmit(event: Event, form: HTMLFormElement) { event.preventDefault(); const data = Object.fromEntries(new FormData(form)); this.result.set(`Submitted ${JSON.stringify(data)}`); }}<script setup lang="ts">import { ref, useTemplateRef } from 'vue';import '@golemui/gui-components/button';import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
const form = useTemplateRef('form');const result = ref('');
function onSubmit() { if (!form.value) return; const data = Object.fromEntries(new FormData(form.value)); result.value = `Submitted ${JSON.stringify(data)}`;}</script>
<template> <form id="time-form" ref="form" @submit.prevent="onSubmit"> <div class="gui-grid gui-grid--row"> <div class="gui-grid__cell gui-grid__cell--span-3"> <gui-time label="Opening time" name="opensAt" min-time="06:00:00" max-time="12:00:00" max-time-message="Open by noon at the latest." :required="true" ></gui-time> </div> <div class="gui-grid__cell"> <gui-button type="submit" label="Save"></gui-button> </div> </div> <p id="time-form-result" role="status">{{ result }}</p> </form></template>import { LitElement, html } from 'lit';import { customElement, query, state } from 'lit/decorators.js';import '@golemui/gui-components/button';import '@golemui/gui-components/time-input';import '@golemui/gui-components/index.css';
@customElement('time-native-form')export class TimeNativeForm extends LitElement { @query('form') private form!: HTMLFormElement; @state() private data?: Record<string, FormDataEntryValue>;
protected override createRenderRoot() { return this; }
private onSubmit(event: SubmitEvent) { event.preventDefault(); this.data = Object.fromEntries(new FormData(this.form)); }
override render() { return html` <form id="time-form" @submit=${this.onSubmit}> <div class="gui-grid gui-grid--row"> <div class="gui-grid__cell gui-grid__cell--span-3"> <gui-time label="Opening time" name="opensAt" min-time="06:00:00" max-time="12:00:00" max-time-message="Open by noon at the latest." required ></gui-time> </div> <div class="gui-grid__cell"> <gui-button type="submit" label="Save"></gui-button> </div> </div> <p role="status"> ${this.data && `Submitted ${JSON.stringify(this.data)}`} </p> </form> `; }}<form id="time-form"> <div class="gui-grid gui-grid--row"> <div class="gui-grid__cell gui-grid__cell--span-3"> <gui-time label="Opening time" name="opensAt" min-time="06:00:00" max-time="12:00:00" max-time-message="Open by noon at the latest." required ></gui-time> </div> <div class="gui-grid__cell"> <gui-button type="submit" label="Save"></gui-button> </div> </div> <p id="time-form-result" role="status"></p></form>
<script type="module"> const form = document.querySelector('#time-form');
form.addEventListener('submit', (event) => { event.preventDefault(); const data = Object.fromEntries(new FormData(form)); document.querySelector('#time-form-result').textContent = `Submitted ${JSON.stringify(data)}`; });</script>How the elements submit, validate and reset is in Native forms.
Styling
Section titled “Styling”Anatomy
Section titled “Anatomy”<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 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>| Class | Part |
|---|---|
gui-field | The element itself. Lines its parts up with the fields next to it in a gui-grid row. |
gui-label, gui-label__text, gui-widget-hint | The label, its text with the required marker, and the hint. |
gui-widget | The box around the control. |
gui-widget-input, gui-parts, gui-time-input | The group of parts, the part that looks like a field. |
gui-parts-ring | The same group: draws the focus ring and the error border around all the parts. |
gui-parts__time-cluster, gui-time-input__time-cluster | The hour and minute, kept left to right in a right-to-left page. |
gui-parts__touch-target, gui-time-input__touch-target | The box around one part, its touch target. |
gui-parts__part, gui-time-input__part | One part, with its data-type: an <input> for hour and minute. |
gui-parts__dayperiod, gui-time-input__dayperiod | The AM/PM toggle, a <button>. |
gui-parts__visual-underline | The line under the focused part. |
gui-time-input__separator | A separator between parts, from the locale. |
gui-calendar--icon, gui-widget-icon | On the group when there is an icon, and the icon itself. |
gui-validator, gui-validator__error | The 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.
Tokens
Section titled “Tokens”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.
/* 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.
Accessibility
Section titled “Accessibility”- Name. The parts sit in a group that the
labelnames. Without a label the group has no name, and development builds log a warning. - Parts. The hour and minute are spin buttons named
HourandMinute, with their range and current number. The AM/PM toggle is a button namedAM/PM. Rename them withhour-aria-label,minute-aria-labelandday-period-aria-label, or translate them for every element under the keyshour,minuteanddayPeriod. - 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
hintdescribes the group, and errors mark it witharia-invalidandaria-errormessage, as on the Date input.
| Key | Action |
|---|---|
| Tab | Moves focus to the first part, and out of the field. |
| 0 to 9 | Type 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. |
| Space | On the AM/PM toggle, switches it. |
| ← / → | Move to the part on the left or right, in the order you see them. |
| Backspace / Delete | Delete digits. Leaving a part empty clears the value. |
What every element shares, such as translating the browser messages, is in Accessibility.