Time field

The time input of the design system. React <TimeField> (packages/ui/src/components/TimeField.tsx) emits .dp-field.time and, when open, the list .dp-timelist / .dp-topt inside a Picker panel. It replaces native <input type="time">: the value can be typed ("930", "9:30", "půl 10", "čtvrt na 10") and the list is a quick pick, not the only path.

When to use

  • A single time of day: task time ("Přidat čas" in the task dialog), attendance stamp.
  • The "od" and "do" ends of an event; the "do" end gets getStart so it offers only times after the start, shows the duration next to each option and accepts a duration ("+30", "+1h", "1,5h", "90m").
  • A coarser list where quarter hours are noise: step={30} (the typed value still takes any minute).

When not to use

  • Date and time of an event together — use Date-time range, which composes two Time fields with a Date field.
  • Duration alone (minutes) — a numeric input; Time field is a clock time.
  • A native <input type="time"> anywhere in the app (canon since 21 Aug 2026).

Anatomy

  • Anchor .dp-anchor around the field; the panel is portalled and positioned to it.
  • Field .dp-field.time: 88×32px, same border, radius and focus ring as Date field; no trigger icon — the list opens with ↓ or after typing.
  • Input .dp-input: 400 13px var(--font-sans), placeholder "–", value shown as fmtHm in h23 ("9:30", "14:00").
  • List .dp-timelist: width 132px, max height 264px, role="listbox"; options .dp-topt 30px rows, 500 13px, .on = --accent-ink 600 (selected has no fill); duration column .d in --overline --fg-muted when getStart is set.
  • States: focus-within ring, .disabled (--surface-75, --border, muted text). There is no error state; an unparsable text reverts to the last value on blur.
  • Value contract: minutes from midnight (0–1440) or null; convert to HH:mm for the API.

Best practices

Do

  • Pair "od" and "do" in .dp-timegroup with .dp-sep "–" and give the end field getStart.
  • Keep step={15} by default; use 30 only where the schedule is coarse (room booking).
  • Wrap a standalone time in <Field label="Čas"> or the panel row .dp-timerow with the clock icon.

Don't

  • A select with 96 options or a spinner instead of this field.
  • Widening the field to the form column — 88px is the content width of "23:45".
  • Filling the list with the duration column when there is no start (getStart only on the end field).

Content

  • Times in 24-hour h:mm with no leading zero ("9:30", "14:00"); durations by fmtDur ("45 min", "1 h", "1 h 30 min").
  • Placeholder "–" — the field is small, no words fit.
  • ariaLabel default "Čas"; use "Od" / "Do" for the two ends.
  • Parser notes (not rendered by the field, available from parseTimeInput): "Nerozumím — zkus 9:30, 930 nebo „půl 10“", "Hodina je 0–23", "Minuta je 0–59", "Délka musí být kladná".
  • date-field — the date part next to it.
  • date-time-range — the canonical composition for events.
  • picker-panel — hosts the time list.

Input rule — approved exception (owner, 1. 10. 2026, acrm !4331)

The binding rule „structured value = mask, never free text“ applies with one approved exception: TimeField accepts a closed vocabulary instead of a fixed separator mask, because people type and say time in several forms. Conditions (all mandatory):

  • Template visible: placeholder hh:mm (in the Do field hh:mm nebo +30).
  • Only characters that can form a valid entry are accepted while typing: digits, : . , space, +, and the words půl / čtvrt / tři čtvrtě / na / h / m / min. Anything else (@, #, /, other letters) is refused on input.
  • Accepted forms (all = 9:05): 9:5, 0905, 905, 9:05, 9.05, 9,05; 9 = 9:00; půl 10, čtvrt na 10. In the Do field also a duration: +30, 1,5h, 90m. A comma is a dot except inside a duration with a unit.
  • Range errors show immediately while typing, under the field in --critical-ink with aria-invalid + aria-describedby (Hodina je 0–23, Minuta je 0–59). „Nerozumím…“ only after leaving the field; the text and the error stay, nothing is reverted silently.
  • Only a complete valid value is saved; after leaving the field it is shown normalised (9:05).
  • Contract test covers the accepted and refused forms (19 cases).

Source: docs/date-time/time-field.usage.md · GitLab