Canonical time choices around a native text input, with labels, validation, reset and form submission owned by the input. Use cem-datepicker for a date and cem-autocomplete for general suggestions.
Full examples and variation matrix · Property playground · Automated stories
Click the input or toggle; ArrowUp/Down navigates, Enter commits, Escape closes and Tab follows native focus. Other editing keys remain native. Programmatic value changes are silent.
{slice @name=min | 09:00}
{cem-field @label="min" @value="{$datadom.slices.min}" @slice=min @slice-event=input @slice-value="$target.value"}
{slice @name=max | 11:00}
{cem-field @label="max" @value="{$datadom.slices.max}" @slice=max @slice-event=input @slice-value="$target.value"}
{slice @name=interval | 30}
{cem-field @label="interval" @value="{$datadom.slices.interval}" @slice=interval @slice-event=input @slice-value="$target.value"}
{slice @name=label | Meeting time}
{cem-field @label="label" @value="{$datadom.slices.label}" @slice=label @slice-event=input @slice-value="$target.value"}
{slice @name=value | 09:30}
{cem-field @label="value" @value="{$datadom.slices.value}" @slice=value @slice-event=input @slice-value="$target.value"}
{slice @name=name | meeting}
{cem-field @label="name" @value="{$datadom.slices.name}" @slice=name @slice-event=input @slice-value="$target.value"}
{slice @name=form | }
{cem-field @label="form" @value="{$datadom.slices.form}" @slice=form @slice-event=input @slice-value="$target.value"}
{slice @name=class | }
{cem-field @label="class" @value="{$datadom.slices.class}" @slice=class @slice-event=input @slice-value="$target.value"}
{slice @name=dir | ltr}
{fieldset @role=group @aria-label="dir" @slice=dir @slice-event=change @slice-value="$target.value" | {legend | dir}{cem-radio @name="property-dir" @value="ltr" @label="ltr" @checked={if datadom.slices.dir == "ltr" {true} else {null}}}{cem-radio @name="property-dir" @value="rtl" @label="rtl" @checked={if datadom.slices.dir == "rtl" {true} else {null}}}}
{slice @name=disabled | absent}
{fieldset @role=group @aria-label="disabled" @slice=disabled @slice-event=change @slice-value="$target.value" | {legend | disabled}{cem-radio @name="property-disabled" @value="absent" @label="absent" @checked={if datadom.slices.disabled == "absent" {true} else {null}}}{cem-radio @name="property-disabled" @value="present" @label="present" @checked={if datadom.slices.disabled == "present" {true} else {null}}}}
{slice @name=required | absent}
{fieldset @role=group @aria-label="required" @slice=required @slice-event=change @slice-value="$target.value" | {legend | required}{cem-radio @name="property-required" @value="absent" @label="absent" @checked={if datadom.slices.required == "absent" {true} else {null}}}{cem-radio @name="property-required" @value="present" @label="present" @checked={if datadom.slices.required == "present" {true} else {null}}}}
{slice @name=invalid | absent}
{fieldset @role=group @aria-label="invalid" @slice=invalid @slice-event=change @slice-value="$target.value" | {legend | invalid}{cem-radio @name="property-invalid" @value="absent" @label="absent" @checked={if datadom.slices.invalid == "absent" {true} else {null}}}{cem-radio @name="property-invalid" @value="present" @label="present" @checked={if datadom.slices.invalid == "present" {true} else {null}}}}
{slice @name=readonly | absent}
{fieldset @role=group @aria-label="readonly" @slice=readonly @slice-event=change @slice-value="$target.value" | {legend | readonly}{cem-radio @name="property-readonly" @value="absent" @label="absent" @checked={if datadom.slices.readonly == "absent" {true} else {null}}}{cem-radio @name="property-readonly" @value="present" @label="present" @checked={if datadom.slices.readonly == "present" {true} else {null}}}}
{slice @name=hidden | absent}
{fieldset @role=group @aria-label="hidden" @slice=hidden @slice-event=change @slice-value="$target.value" | {legend | hidden}{cem-radio @name="property-hidden" @value="absent" @label="absent" @checked={if datadom.slices.hidden == "absent" {true} else {null}}}{cem-radio @name="property-hidden" @value="present" @label="present" @checked={if datadom.slices.hidden == "present" {true} else {null}}}}
{slice @name=indicator | underline}
{fieldset @role=group @aria-label="indicator" @slice=indicator @slice-event=change @slice-value="$target.value" | {legend | indicator}{cem-radio @name="property-indicator" @value="underline" @label="underline" @checked={if datadom.slices.indicator == "underline" {true} else {null}}}{cem-radio @name="property-indicator" @value="outline" @label="outline" @checked={if datadom.slices.indicator == "outline" {true} else {null}}}}
{slice @name=toggle | present}
{fieldset @role=group @aria-label="toggle" @slice=toggle @slice-event=change @slice-value="$target.value" | {legend | toggle}{cem-radio @name="property-toggle" @value="present" @label="present" @checked={if datadom.slices.toggle == "present" {true} else {null}}}{cem-radio @name="property-toggle" @value="absent" @label="absent" @checked={if datadom.slices.toggle == "absent" {true} else {null}}}}
{form | {cem-timepicker @min="{$datadom.slices.min}" @max="{$datadom.slices.max}" @interval="{$datadom.slices.interval}" @class="{$datadom.slices.class}" @dir="{$datadom.slices.dir}" @indicator="{$datadom.slices.indicator}" @disabled={if datadom.slices.disabled == "present" {true} else {null}} @required={if datadom.slices.required == "present" {true} else {null}} @invalid={if datadom.slices.invalid == "present" {true} else {null}} @hidden={if datadom.slices.hidden == "present" {true} else {null}} | {input @slot=input @type=text @aria-label="{$datadom.slices.label}" @name="{$datadom.slices.name}" @form={if datadom.slices.form {datadom.slices.form} else {null}} @readonly={if datadom.slices.readonly == "present" {true} else {null}} | {attribute @name=value @value={datadom.slices.value}}}
{cem:if @test='datadom.slices.toggle == "present"' | {button @slot=toggle @type=button @aria-label="Choose time" | Choose}}}{cem-action @type=reset @label="Reset values"}}
{cem-module-url @slice=sourceUrl @src="@epa-wg/cem-components/components/cem-timepicker/cem-timepicker.xhtml"}{cem:if @test="datadom.slices.sourceUrl" | {p | {a @href="{$datadom.slices.sourceUrl}" | Open canonical XHTML}}{cem-demo-element @legend="Canonical source" @src="{$datadom.slices.sourceUrl}" @type=xml @demo=false}}