Skip to content

Selection

Time pickers

Lets people select a time on a clock dial, in text fields or on scroll wheels.

Examples

Clock dial

Hours, then minutes on the dial, with AM / PM in 12-hour locales. Drag the hand or use the arrow keys.

The live demo runs with JavaScript. Its code is below.

React HTML
import { useState } from 'react';
import { TimePicker, type TimeValue } from '@kyralabs/m3exp-web/react';

export default function Dial() {
  const [time, setTime] = useState<TimeValue>({ hour: 7, minute: 30 });
  return (
    <div>
      <TimePicker value={time} onChange={setTime} layout="vertical" />
      <p>
        Alarm: {String(time.hour).padStart(2, '0')}:{String(time.minute).padStart(2, '0')}
      </p>
    </div>
  );
}
<m3e-time-picker id="alarm" hour="7" minute="30" layout="vertical"></m3e-time-picker>
<p>Alarm: <output id="alarm-value">07:30</output></p>
<script>
  document.getElementById('alarm').addEventListener('change', (event) => {
    const { hour, minute } = event.detail;
    document.getElementById('alarm-value').textContent =
      `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
  });
</script>

Run the HTML version (custom elements, no framework).

Text input

Type the hours and minutes; here in 24-hour time.

The live demo runs with JavaScript. Its code is below.

React HTML
import { TimeInput } from '@kyralabs/m3exp-web/react';

export default function Input() {
  return <TimeInput defaultValue={{ hour: 14, minute: 5 }} is24Hour />;
}
<m3e-time-input hour="14" minute="5" hour-cycle="24"></m3e-time-input>

Run the HTML version (custom elements, no framework).

Scroll wheels

The expressive scroll wheels (always vibrant).

The live demo runs with JavaScript. Its code is below.

React HTML
import { TimeScroll } from '@kyralabs/m3exp-web/react';

export default function Scroll() {
  return <TimeScroll defaultValue={{ hour: 9, minute: 45 }} />;
}
<m3e-time-scroll hour="9" minute="45"></m3e-time-scroll>

Run the HTML version (custom elements, no framework).

In a dialog

Compose's TimePickerDialog: a title, the picker, Cancel and OK.

The live demo runs with JavaScript. Its code is below.

React HTML
import { useState } from 'react';
import { Button, TimePicker, TimePickerDialog, type TimeValue } from '@kyralabs/m3exp-web/react';

export default function Dialog() {
  const [open, setOpen] = useState(false);
  const [time, setTime] = useState<TimeValue>({ hour: 18, minute: 0 });
  const [draft, setDraft] = useState(time);
  return (
    <>
      <Button
        variant="tonal"
        onPress={() => {
          setDraft(time);
          setOpen(true);
        }}
      >
        Pick a time
      </Button>
      <p>
        Time: {String(time.hour).padStart(2, '0')}:{String(time.minute).padStart(2, '0')}
      </p>
      <TimePickerDialog
        aria-label="Select time"
        title="Select time"
        isOpen={open}
        onOpenChange={setOpen}
        dismissButton={
          <Button
            variant="text"
            onPress={() => {
              setOpen(false);
            }}
          >
            Cancel
          </Button>
        }
        confirmButton={
          <Button
            variant="text"
            onPress={() => {
              setTime(draft);
              setOpen(false);
            }}
          >
            OK
          </Button>
        }
      >
        <TimePicker value={draft} onChange={setDraft} />
      </TimePickerDialog>
    </>
  );
}
<button type="button" id="open-time" class="m3e-button m3e-button--tonal">Pick a time</button>
<p>Time: <output id="time-value">18:00</output></p>
<m3e-dialog id="time-dialog" variant="custom" label="Select time">
  <div class="m3e-time-picker-dialog">
    <div class="m3e-time-picker-dialog__title">Select time</div>
    <div class="m3e-time-picker-dialog__content">
      <m3e-time-picker hour="18" minute="0"></m3e-time-picker>
    </div>
    <div class="m3e-time-picker-dialog__actions">
      <span class="m3e-time-picker-dialog__spacer"></span>
      <button type="button" class="m3e-button m3e-button--text" data-action="cancel">Cancel</button>
      <button type="button" class="m3e-button m3e-button--text" data-action="ok">OK</button>
    </div>
  </div>
</m3e-dialog>
<script>
  const dialog = document.getElementById('time-dialog');
  const picker = dialog.querySelector('m3e-time-picker');
  document.getElementById('open-time').addEventListener('click', () => dialog.show());
  dialog.addEventListener('click', (event) => {
    const action = event.target.closest('[data-action]')?.dataset.action;
    if (action === 'ok') {
      document.getElementById('time-value').textContent =
        `${String(picker.hour).padStart(2, '0')}:${String(picker.minute).padStart(2, '0')}`;
    }
    if (action) dialog.close();
  });
</script>

Run the HTML version (custom elements, no framework).

API

React

<TimePicker>

Time picker with a clock dial (COMPONENT_SPEC §28; Compose TimePicker): the hour / minute selectors, AM/PM (12-hour) and the dial, built and run by m3e-elements' TimePickerLayout (the code <m3e-time-picker> runs, so both layers render one DOM contract).

Prop Type Default Description
vibrant boolean Compose's vibrant (expressive) TimePicker overload.
layout "horizontal" | "vertical" | "auto" TimePickerLayoutType; auto (default): horizontal in a landscape window, as Compose.
value TimeValue The time (controlled).
defaultValue TimeValue The initial time (uncontrolled; default 00:00, as rememberTimePickerState).
is24Hour boolean 24-hour clock; default: the locale's (owner decision M10 T5).
selection "hour" | "minute" Which of hour / minute is being picked (controlled).
defaultSelection "hour" | "minute" The initial selection (default hour).
locale string BCP 47 locale for the digits and the default clock; default: the closest lang.
labels Partial<TimePickerStrings> String overrides (Compose's strings by default).
onChange (value: TimeValue) => void The user picked a time.
onSelectionChange (selection: TimePickerSelection) => void

Also accepts HTML attributes not listed here.

<TimeInput>

Time picker with text fields (COMPONENT_SPEC §28; Compose TimeInput), built and run by m3e-elements' TimeInputLayout (shared with <m3e-time-input>).

Prop Type Default Description
vibrant boolean Compose's vibrant TimeInput overload.
uncontained boolean Compose's TimeInput with a toggle: taller fields and a side column of AM, PM and a mode toggle button (to the scroll picker), which calls onModeToggle.
value TimeValue The time (controlled).
defaultValue TimeValue The initial time (uncontrolled; default 00:00, as rememberTimePickerState).
is24Hour boolean 24-hour clock; default: the locale's (owner decision M10 T5).
selection "hour" | "minute" Which of hour / minute is being picked (controlled).
defaultSelection "hour" | "minute" The initial selection (default hour).
locale string BCP 47 locale for the digits and the default clock; default: the closest lang.
labels Partial<TimePickerStrings> String overrides (Compose's strings by default).
onModeToggle (next: TimePickerDisplayMode) => void The side column's mode toggle was pressed; next is the mode it asks for ('scroll').
onChange (value: TimeValue) => void The user picked a time.
onSelectionChange (selection: TimePickerSelection) => void

Also accepts HTML attributes not listed here.

<TimeScroll>

Time picker with scroll wheels (COMPONENT_SPEC §28; Compose TimeScroll, vibrant only), built and run by m3e-elements' TimeScrollLayout (shared with <m3e-time-scroll>).

Prop Type Default Description
uncontained boolean Compose's TimeScroll with a toggle (see TimeInputProps.uncontained; to the text input).
value TimeValue The time (controlled).
defaultValue TimeValue The initial time (uncontrolled; default 00:00, as rememberTimePickerState).
is24Hour boolean 24-hour clock; default: the locale's (owner decision M10 T5).
selection "hour" | "minute" Which of hour / minute is being picked (controlled).
defaultSelection "hour" | "minute" The initial selection (default hour).
locale string BCP 47 locale for the digits and the default clock; default: the closest lang.
labels Partial<TimePickerStrings> String overrides (Compose's strings by default).
onModeToggle (next: TimePickerDisplayMode) => void The side column's mode toggle was pressed; next is the mode it asks for ('input').
onChange (value: TimeValue) => void The user picked a time.
onSelectionChange (selection: TimePickerSelection) => void

Also accepts HTML attributes not listed here.

<TimePickerDialog>

Time picker dialog (Compose TimePickerDialog): the title, the picker, the actions (mode toggle, dismiss, confirm) on a dialog surface, in m3e-react's <BasicAlertDialog> (M9 dialog motion, focus and dismissal).

Prop Type Default Description
title ReactNode TimePickerDialogDefaults.Title: e.g. "Select Time" (picker) or "Enter Time" (input).
confirmButton required ReactNode The confirm button (a text button, enabled while the input is valid).
modeToggleButton ReactNode The mode toggle at the start of the actions (<TimePickerModeToggle>).
children required ReactNode The picker.
aria-label string The dialog's name (default "Dialog", Compose's pane title).
isOpen boolean Open (controlled).
defaultOpen boolean The initial open state (uncontrolled).
dismissButton ReactNode
onOpenChange (isOpen: boolean) => void Called when the dialog asks to close (Escape, a press on the scrim, the full-screen close button, a browser close request: Compose's onDismissRequest) with false. Controlled dialogs close when isOpen becomes false; leave it true to keep the dialog open.

Also accepts HTML attributes not listed here.

<VibrantTimePickerDialog>

Vibrant time picker dialog (Compose VibrantTimePickerDialog): no title, tighter padding.

Prop Type Default Description
title ReactNode TimePickerDialogDefaults.Title: e.g. "Select Time" (picker) or "Enter Time" (input).
confirmButton required ReactNode The confirm button (a text button, enabled while the input is valid).
modeToggleButton ReactNode The mode toggle at the start of the actions (<TimePickerModeToggle>).
children required ReactNode The picker.
aria-label string The dialog's name (default "Dialog", Compose's pane title).
isOpen boolean Open (controlled).
defaultOpen boolean The initial open state (uncontrolled).
dismissButton ReactNode
onOpenChange (isOpen: boolean) => void Called when the dialog asks to close (Escape, a press on the scrim, the full-screen close button, a browser close request: Compose's onDismissRequest) with false. Controlled dialogs close when isOpen becomes false; leave it true to keep the dialog open.

Also accepts HTML attributes not listed here.

<TimePickerModeToggle>

TimePickerDialogDefaults.DisplayModeToggle / ScrollDisplayModeToggle: an icon button (keyboard, schedule or swipe_vertical, on-surface-variant) with a plain tooltip above that repeats its name.

Prop Type Default Description
displayMode required "picker" | "input" | "scroll" The mode shown now.
scroll boolean Between input and scroll (ScrollDisplayModeToggle) instead of picker and input (DisplayModeToggle).
labels Partial<TimePickerStrings>
onDisplayModeChange required (next: TimePickerDisplayMode) => void Pressed: next is the mode to show (picker ↔ input, or input ↔ scroll with scroll).

Custom elements

<m3e-time-picker>

import '@kyralabs/m3e-elements/time-picker.js';

<m3e-time-picker hour="7" minute="30"> (COMPONENT_SPEC §28; Compose TimePicker): the dial picker. Attributes hour (0–23), minute, hour-cycle="12 | 24" (default: the locale's, from lang), selection="hour | minute", vibrant (the expressive overload), layout="auto | vertical | horizontal" (auto: horizontal in a landscape window, as Compose). Property labels (string overrides). Events change (detail: { hour, minute }) and selection-change (detail: { selection }). The DOM is m3e-css's .m3e-time-picker contract, built and run by TimePickerLayout (shared with m3e-react).

Attribute Property Type Notes
hour hour number
minute minute number
hour-cycle hourCycle string
selection selection string Reflected.
vibrant vibrant boolean Reflected.
layout layout string
Event Detail Description
change TimePickerChangeDetail The user changed the time (the inputs' native input / change stop inside).
selection-change TimePickerSelectionChangeDetail The selected field (hour or minute) changed.

<m3e-time-input>

import '@kyralabs/m3e-elements/time-input.js';

<m3e-time-input hour="7" minute="30"> (COMPONENT_SPEC §28; Compose TimeInput): the text input picker. The <m3e-time-picker> attributes, events and labels (no layout), plus uncontained (Compose's TimeInput with a toggle: the side column with AM, PM and a mode toggle button, which fires mode-toggle). Built and run by TimeInputLayout (shared with m3e-react).

Attribute Property Type Notes
hour hour number
minute minute number
hour-cycle hourCycle string
selection selection string Reflected.
vibrant vibrant boolean Reflected.
uncontained uncontained boolean Reflected.
Event Detail Description
mode-toggle null The uncontained side column's mode toggle was pressed.

<m3e-time-scroll>

import '@kyralabs/m3e-elements/time-scroll.js';

<m3e-time-scroll hour="7" minute="30"> (COMPONENT_SPEC §28; Compose TimeScroll, vibrant only): the scroll wheel picker. The <m3e-time-input> attributes and events (vibrant has no effect: TimeScroll is always vibrant). Built and run by TimeScrollLayout (shared with m3e-react).

Attribute Property Type Notes
hour hour number
minute minute number
hour-cycle hourCycle string
selection selection string Reflected.
vibrant vibrant boolean Reflected.
uncontained uncontained boolean Reflected.
Event Detail Description
mode-toggle null The uncontained side column's mode toggle was pressed.

CSS

time-picker.css

@import '@kyralabs/m3e-css/time-picker.css';

Time pickers (COMPONENT_SPEC §28): Compose's TimePicker (the dial), TimeInput, TimeScroll and the TimePickerDialog / VibrantTimePickerDialog surfaces, each baseline or vibrant (expressive; TimeScroll is vibrant only). The dial, the inputs and the wheels need m3e-elements' time picker layouts (shared with m3e-react), which build this DOM and write its state; the CSS draws it.

<div class="m3e-time-picker [m3e-time-picker--vibrant] [m3e-time-picker--horizontal]
            [m3e-time-picker--24h]" data-selection="hour | minute">
  <div class="m3e-time-picker__display">
    <div class="m3e-time-picker__fields">           (always left to right)
      <button class="m3e-time-picker__selector" role="radio" aria-checked="true">
        <span class="m3e-time-picker__value">07</span></button>
      <span class="m3e-time-picker__separator" aria-hidden="true">:</span>
      <button class="m3e-time-picker__selector" role="radio" aria-checked="false">…</button>
    </div>
    <div class="m3e-time-picker__period" role="radiogroup">   (12-hour only)
      <button class="m3e-time-picker__period-item" role="radio" aria-checked="true">AM</button>
      <button class="m3e-time-picker__period-item" role="radio" aria-checked="false">PM</button>
    </div>
  </div>
  <div class="m3e-time-picker__dial" style="--_m3e-time-picker-cos: …; --_m3e-time-picker-sin: …">
    <div class="m3e-time-picker__face" data-face="hour" data-active role="radiogroup">
      <span class="m3e-time-picker__label [m3e-time-picker__label--inner]" role="radio"
            style="--_m3e-time-picker-label-cos: …; --_m3e-time-picker-label-sin: …">12</span> …
    </div>
    <div class="m3e-time-picker__face" data-face="minute" role="radiogroup">…</div>
    <span class="m3e-time-picker__handle"></span>
    <span class="m3e-time-picker__track"></span>
    <span class="m3e-time-picker__center"></span>
    <div class="m3e-time-picker__highlight" aria-hidden="true">   (the faces again, on-primary,
      <div class="m3e-time-picker__face" data-face="hour" data-active>   clipped to the handle; each
        <span class="m3e-time-picker__label" data-label="12"></span> …     label's text is generated
      </div> …                                                           from data-label)
    </div>
  </div>
</div>

<div class="m3e-time-input [m3e-time-input--vibrant] [m3e-time-input--uncontained]">
  <div class="m3e-time-input__fields">
    <div class="m3e-time-input__field" [data-selected] [data-invalid]>
      <input class="m3e-time-input__input" inputmode="numeric" role="spinbutton" value="07">
      <span class="m3e-time-input__supporting">Hour</span>    (baseline, or invalid)
    </div>
    <span class="m3e-time-input__separator" aria-hidden="true">:</span>
    <div class="m3e-time-input__field">…</div>
  </div>
  <div class="m3e-time-picker__period">…</div>   or, uncontained, <div class="m3e-time-picker__side">
</div>                                              AM, PM and the mode toggle </div>

<div class="m3e-time-scroll [m3e-time-scroll--uncontained]">
  <div class="m3e-time-scroll__fields">
    <div class="m3e-time-scroll__field" role="spinbutton" tabindex="0">
      <span class="m3e-time-scroll__item" [data-selected]
            style="--_m3e-time-scroll-offset: -1">06</span> …
    </div>
    <span class="m3e-time-scroll__separator" aria-hidden="true">:</span> …
  </div>
  <div class="m3e-time-picker__period">…</div> | <div class="m3e-time-picker__side">…</div>
</div>

<dialog class="m3e-dialog m3e-dialog--custom"> … <div class="m3e-dialog__container">
  <div class="m3e-time-picker-dialog [m3e-time-picker-dialog--vibrant]">
    <div class="m3e-time-picker-dialog__title">Select time</div>      (baseline)
    <div class="m3e-time-picker-dialog__content">a picker</div>
    <div class="m3e-time-picker-dialog__actions">[mode toggle] <span class="m3e-time-picker-dialog__spacer"></span>
      Cancel OK</div>
  </div>
</div></dialog>
140 custom properties it reads
Custom property Default
--m3e-comp-minimum-interactive-component-size 48px
--m3e-comp-small-icon-button-container-height 40px
--m3e-comp-small-icon-button-icon-size 24px
--m3e-comp-time-input-period-selector-container-height 72px
--m3e-comp-time-input-period-selector-container-width 52px
--m3e-comp-time-input-time-field-container-height 72px
--m3e-comp-time-input-time-field-container-shape var(--m3e-sys-shape-corner-small)
--m3e-comp-time-input-time-field-container-width 96px
--m3e-comp-time-input-time-field-label-text-font var(--m3e-sys-typescale-display-medium-font)
--m3e-comp-time-input-time-field-label-text-size var(--m3e-sys-typescale-display-medium-size)
--m3e-comp-time-input-time-field-label-text-tracking var(--m3e-sys-typescale-display-medium-tracking)
--m3e-comp-time-input-time-field-label-text-weight var(--m3e-sys-typescale-display-medium-weight)
--m3e-comp-time-input-time-field-separator-color var(--m3e-sys-color-on-surface)
--m3e-comp-time-input-time-field-supporting-text-color var(--m3e-sys-color-on-surface-variant)
--m3e-comp-time-input-time-field-supporting-text-font var(--m3e-sys-typescale-body-small-font)
--m3e-comp-time-input-time-field-supporting-text-line-height var(--m3e-sys-typescale-body-small-line-height)
--m3e-comp-time-input-time-field-supporting-text-size var(--m3e-sys-typescale-body-small-size)
--m3e-comp-time-input-time-field-supporting-text-tracking var(--m3e-sys-typescale-body-small-tracking)
--m3e-comp-time-input-time-field-supporting-text-weight var(--m3e-sys-typescale-body-small-weight)
--m3e-comp-time-picker-clock-dial-color var(--m3e-sys-color-surface-container-highest)
--m3e-comp-time-picker-clock-dial-container-size 256px
--m3e-comp-time-picker-clock-dial-label-text-color-selected var(--m3e-sys-color-on-primary)
--m3e-comp-time-picker-clock-dial-label-text-color-unselected var(--m3e-sys-color-on-surface)
--m3e-comp-time-picker-clock-dial-label-text-font var(--m3e-sys-typescale-body-large-font)
--m3e-comp-time-picker-clock-dial-label-text-line-height var(--m3e-sys-typescale-body-large-line-height)
--m3e-comp-time-picker-clock-dial-label-text-size var(--m3e-sys-typescale-body-large-size)
--m3e-comp-time-picker-clock-dial-label-text-tracking var(--m3e-sys-typescale-body-large-tracking)
--m3e-comp-time-picker-clock-dial-label-text-weight var(--m3e-sys-typescale-body-large-weight)
--m3e-comp-time-picker-clock-dial-selector-center-container-color var(--m3e-sys-color-primary)
--m3e-comp-time-picker-clock-dial-selector-center-container-shape var(--m3e-sys-shape-corner-full)
--m3e-comp-time-picker-clock-dial-selector-center-container-size 8px
--m3e-comp-time-picker-clock-dial-selector-handle-container-color var(--m3e-sys-color-primary)
--m3e-comp-time-picker-clock-dial-selector-handle-container-shape var(--m3e-sys-shape-corner-full)
--m3e-comp-time-picker-clock-dial-selector-track-container-color var(--m3e-sys-color-primary)
--m3e-comp-time-picker-clock-dial-selector-track-container-width 2px
--m3e-comp-time-picker-clock-dial-shape var(--m3e-sys-shape-corner-full)
--m3e-comp-time-picker-dialog-actions-gap 8px
--m3e-comp-time-picker-dialog-container-color var(--m3e-sys-color-surface-container-high)
--m3e-comp-time-picker-dialog-container-shape var(--m3e-sys-shape-corner-extra-large)
--m3e-comp-time-picker-dialog-landscape-actions-bottom 8px
--m3e-comp-time-picker-dialog-landscape-content-actions 4px
--m3e-comp-time-picker-dialog-landscape-content-top 16px
--m3e-comp-time-picker-dialog-padding 24px
--m3e-comp-time-picker-dialog-padding-bottom 24px
--m3e-comp-time-picker-dialog-padding-top 24px
--m3e-comp-time-picker-dialog-title-font var(--m3e-sys-typescale-label-medium-font)
--m3e-comp-time-picker-dialog-title-line-height var(--m3e-sys-typescale-label-medium-line-height)
--m3e-comp-time-picker-dialog-title-padding-bottom 20px
--m3e-comp-time-picker-dialog-title-size var(--m3e-sys-typescale-label-medium-size)
--m3e-comp-time-picker-dialog-title-tracking var(--m3e-sys-typescale-label-medium-tracking)
--m3e-comp-time-picker-dialog-title-weight var(--m3e-sys-typescale-label-medium-weight)
--m3e-comp-time-picker-display-gap 36px
--m3e-comp-time-picker-face-bottom-margin 24px
--m3e-comp-time-picker-face-duration var(--m3e-sys-motion-spring-default-effects-duration)
--m3e-comp-time-picker-face-easing var(--m3e-sys-motion-spring-default-effects-easing)
--m3e-comp-time-picker-inner-radius 69px
--m3e-comp-time-picker-input-caret-color var(--m3e-sys-color-primary)
--m3e-comp-time-picker-input-container-color-error var(--m3e-sys-color-error-container)
--m3e-comp-time-picker-input-label-color-error var(--m3e-sys-color-error)
--m3e-comp-time-picker-input-outline-color var(--m3e-sys-color-outline)
--m3e-comp-time-picker-input-outline-color-error var(--m3e-sys-color-error)
--m3e-comp-time-picker-input-outline-color-focused var(--m3e-sys-color-outline)
--m3e-comp-time-picker-input-outline-width 1px
--m3e-comp-time-picker-input-outline-width-focused 2px
--m3e-comp-time-picker-minimum-interactive-size 48px
--m3e-comp-time-picker-outer-radius 101px
--m3e-comp-time-picker-period-container-color var(--m3e-sys-color-surface-container-lowest)
--m3e-comp-time-picker-period-gap 4px
--m3e-comp-time-picker-period-label-weight-selected 700
--m3e-comp-time-picker-period-selector-label-text-font var(--m3e-sys-typescale-title-medium-font)
--m3e-comp-time-picker-period-selector-label-text-line-height var(--m3e-sys-typescale-title-medium-line-height)
--m3e-comp-time-picker-period-selector-label-text-size var(--m3e-sys-typescale-title-medium-size)
--m3e-comp-time-picker-period-selector-label-text-tracking var(--m3e-sys-typescale-title-medium-tracking)
--m3e-comp-time-picker-period-selector-label-text-weight var(--m3e-sys-typescale-title-medium-weight)
--m3e-comp-time-picker-period-shape-pressed 12px
--m3e-comp-time-picker-period-shape-selected 12px
--m3e-comp-time-picker-scroll-field-container-color var(--m3e-sys-color-surface-container-lowest)
--m3e-comp-time-picker-scroll-field-height 200px
--m3e-comp-time-picker-scroll-field-label-color var(--m3e-sys-color-outline)
--m3e-comp-time-picker-scroll-field-label-color-selected var(--m3e-sys-color-on-surface)
--m3e-comp-time-picker-scroll-field-pages 3
--m3e-comp-time-picker-scroll-field-shape var(--m3e-sys-shape-corner-large)
--m3e-comp-time-picker-scroll-field-width 100px
--m3e-comp-time-picker-scroll-item-duration var(--m3e-sys-motion-spring-fast-spatial-duration)
--m3e-comp-time-picker-scroll-item-easing var(--m3e-sys-motion-spring-fast-spatial-easing)
--m3e-comp-time-picker-scroll-item-font var(--m3e-sys-typescale-display-medium-font)
--m3e-comp-time-picker-scroll-item-line-height var(--m3e-sys-typescale-display-medium-line-height)
--m3e-comp-time-picker-scroll-item-selected-font var(--m3e-sys-typescale-display-large-emphasized-font)
--m3e-comp-time-picker-scroll-item-selected-line-height var(--m3e-sys-typescale-display-large-emphasized-line-height)
--m3e-comp-time-picker-scroll-item-selected-size var(--m3e-sys-typescale-display-large-emphasized-size)
--m3e-comp-time-picker-scroll-item-selected-tracking var(--m3e-sys-typescale-display-large-emphasized-tracking)
--m3e-comp-time-picker-scroll-item-selected-weight var(--m3e-sys-typescale-display-large-emphasized-weight)
--m3e-comp-time-picker-scroll-item-size var(--m3e-sys-typescale-display-medium-size)
--m3e-comp-time-picker-scroll-item-tracking var(--m3e-sys-typescale-display-medium-tracking)
--m3e-comp-time-picker-scroll-item-weight var(--m3e-sys-typescale-display-medium-weight)
--m3e-comp-time-picker-separator-offset -4px
--m3e-comp-time-picker-separator-width 24px
--m3e-comp-time-picker-side-item-height 40px
--m3e-comp-time-picker-side-item-min-width 40px
--m3e-comp-time-picker-side-item-padding 4px
--m3e-comp-time-picker-side-period-gap 8px
--m3e-comp-time-picker-side-toggle-gap 16px
--m3e-comp-time-picker-side-toggle-top-24h 84px
--m3e-comp-time-picker-supporting-text-color-error var(--m3e-sys-color-error)
--m3e-comp-time-picker-supporting-text-top 7px
--m3e-comp-time-picker-time-selector-container-height 80px
--m3e-comp-time-picker-time-selector-container-shape var(--m3e-sys-shape-corner-small)
--m3e-comp-time-picker-time-selector-container-width 96px
--m3e-comp-time-picker-time-selector-label-color-error var(--m3e-sys-color-on-error-container)
--m3e-comp-time-picker-time-selector-label-text-font var(--m3e-sys-typescale-display-large-font)
--m3e-comp-time-picker-time-selector-label-text-line-height var(--m3e-sys-typescale-display-large-line-height)
--m3e-comp-time-picker-time-selector-label-text-size var(--m3e-sys-typescale-display-large-size)
--m3e-comp-time-picker-time-selector-label-text-tracking var(--m3e-sys-typescale-display-large-tracking)
--m3e-comp-time-picker-time-selector-label-text-weight var(--m3e-sys-typescale-display-large-weight)
--m3e-comp-time-picker-uncontained-time-field-height 136px
--m3e-comp-time-picker-uncontained-toggle-height 140px
--m3e-comp-time-picker-vibrant-clock-dial-color var(--m3e-sys-color-surface-container-lowest)
--m3e-comp-time-picker-vibrant-dialog-container-color var(--m3e-sys-color-surface-container)
--m3e-comp-time-picker-vibrant-dialog-landscape-padding 24px
--m3e-comp-time-picker-vibrant-dialog-padding 12px
--m3e-comp-time-picker-vibrant-horizontal-gap 52px
--m3e-comp-time-picker-vibrant-input-label-color var(--m3e-sys-color-on-surface)
--m3e-comp-time-picker-vibrant-input-label-color-focused var(--m3e-sys-color-primary)
--m3e-comp-time-picker-vibrant-input-outline-color transparent
--m3e-comp-time-picker-vibrant-input-outline-color-error var(--m3e-sys-color-error)
--m3e-comp-time-picker-vibrant-period-container-color var(--m3e-sys-color-surface-container-lowest)
--m3e-comp-time-picker-vibrant-period-height 120px
--m3e-comp-time-picker-vibrant-period-horizontal-height 40px
--m3e-comp-time-picker-vibrant-period-large-padding 16px
--m3e-comp-time-picker-vibrant-period-padding 8px
--m3e-comp-time-picker-vibrant-period-width 56px
--m3e-comp-time-picker-vibrant-selector-outline-color var(--m3e-sys-color-primary)
--m3e-comp-time-picker-vibrant-selector-outline-width 2px
--m3e-comp-time-picker-vibrant-separator-width 16px
--m3e-comp-time-picker-vibrant-time-field-height 120px
--m3e-comp-time-picker-vibrant-time-field-label-text-font var(--m3e-sys-typescale-display-large-font)
--m3e-comp-time-picker-vibrant-time-field-label-text-size var(--m3e-sys-typescale-display-large-size)
--m3e-comp-time-picker-vibrant-time-field-shape var(--m3e-sys-shape-corner-large)
--m3e-comp-time-picker-vibrant-time-field-width 100px
--m3e-comp-time-picker-vibrant-vertical-gap 12px

Sources

Values come from androidx Compose Material3 1.5.0-beta01 at 19991f2c and from m3.material.io, as cited below from COMPONENT_SPEC §28 and the m3e-css sources.

TimePickerTokens.kt / TimeInputTokens.kt@19991f2c (generated time-picker.css / time-input.css) plus components/time-picker-defaults.css (time-picker-defaults.ts, PARITY.md lines): dial 256dp, labels 48dp on the 101dp / 69dp radii (OuterCircleSizeRadius, InnerCircleRadius), handle 48dp, track 2dp, center 8dp, MaxDistance 74dp; display fields 96 × 80dp (24-hour vertical 114dp), separator 24dp; vibrant fields 100 × 120dp (132dp portrait), uncontained 136dp, separator 16dp, field shape and display-large type (VibrantTimeField*); input fields 96 × 72dp, outline 1dp / 2dp focused in primary; scroll wheels 100dp wide, as tall as the fields, three pages to 200dp (ScrollField), the selected row display-large-emphasized (ScrollFieldDefaults.Item); dialog padding 24dp (landscape 16 / 4 / 8dp, vibrant 12dp), title label-medium, min height for the dial 300dp. AM/PM (owner decision M10 T3): ComposeMaterial3Flags.isUpdatedTimepickerToggleEnabled is on by default, so the period is two toggle buttons (primary-container and bold when selected, surface-container-lowest otherwise, a circle that morphs to 12dp, 4dp apart, no outline), not the tokens' outlined tertiary-container segments. Error colors from the vibrant input colors; the side column (SideControlColumn): AM, PM 8dp below, the mode toggle's icon 16dp below PM (24-hour: the toggle alone at 84dp).

time-picker.css sources

(compose/material3 @ 19991f2c; values in time-picker.css, time-input.css and time-picker-defaults.css, lines in PARITY.md):

  • TimePickerTokens / TimeInputTokens through TimePicker.kt's defaults, with ComposeMaterial3Flags.isUpdatedTimepickerToggleEnabled on (owner decision M10 T3): the AM/PM toggle is two ToggleButtons (CircleShape → 12dp pressed / checked on the fast spatial spring, primary-container checked, surface-container-lowest unchecked, bold when checked, 4dp apart, no outline), not the tokens' outlined tertiary segmented control.
  • VerticalTimePicker / HorizontalTimePicker (L1958–2013): the display (fields + AM/PM) then the 256dp dial, below (vertical) or beside (horizontal); vibrant gaps and sizes (L1454–1479). The layout type is Compose's screen orientation (TimePicker.android.kt), resolved by the layouts (owner decision M10 T6); the dial does not shrink in short windows (gap, T6).
  • ClockFace / drawSelector / CircularLayout (L3270–3480, L3935–3972): labels on a 101dp circle (24-hour: 0, 13–23 on a 69dp one), the 48dp primary handle at the selector's angle with the labels under it in on-primary (Compose's Clear / Xor / DstOver blending), a 2dp track from the center and an 8dp center dot; the faces cross-fade on DefaultEffects.
  • TimeSelector (L3060–3128): a RadioButton surface; vibrant: a 2dp primary border when selected.
  • TimeInputImpl / TimePickerTextField (L2033–2227, L3789–3928): an unselected field is a TimeSelector; the selected one an outlined text field (1dp / 2dp outline borders, error container and border when invalid); "Hour" / "Minute" or the error below (baseline, invalid).
  • TimeScrollImpl / ScrollField (L2230–2380; ScrollField.kt): two infinite wheels of ScrollFieldHeight / 3 rows, the centered row selected (display large emphasized, on-surface) and the others display medium in outline, interpolated on the fast spatial spring.
  • SideControlColumn (L2693–2767): the uncontained variants' AM, PM and mode toggle column.
  • TimePickerDialog.kt: the dialogs' surfaces and their portrait / landscape layouts.
  • Touch targets ≥ 48dp (::after), :focus-visible rings, forced colors, reduced motion (the selector and the wheels jump).