Skip to content
kerfjsGitHub

TimeField

Type a time or pick one from a list, in the 12 or 24 hour clock.

SourcePackage @kerf-js/veneer

Preview

tsx
import { Stack, TimeField } from '@kerf-js/veneer'import type { IsoDate } from '@kerf-js/veneer'export function Clock() {  return (  <Stack gap="group">    <TimeField      label="12-hour"      today={TODAY}      defaultValue="14:30"      hourCycle="h12"    />    <TimeField      label="24-hour"      today={TODAY}      defaultValue="14:30"      hourCycle="h23"    />    <TimeField      label="With seconds"      today={TODAY}      defaultValue="14:30:15"      hourCycle="h23"      seconds    />  </Stack>  )}const TODAY: IsoDate = '2026-11-02'

Installation

npm install @kerf-js/veneer

Usage

tsx
import { TimeField } from '@kerf-js/veneer'

Only some times

slots replaces the list with the times you allow.

tsx
import { TimeField } from '@kerf-js/veneer'import type { IsoDate, IsoTime } from '@kerf-js/veneer'export function Slots() {  return (  <TimeField    label="Onboarding call"    hint="Only the times Priya is free"    today={TODAY}    defaultValue="11:00"    slots={SLOTS}  />  )}const TODAY: IsoDate = '2026-11-02'const SLOTS: IsoTime[] = [  '09:00',  '09:30',  '11:00',  '14:00',  '15:30',  '16:00',]

Office hours

min, max and step shape the list.

tsx
import { TimeField } from '@kerf-js/veneer'import type { IsoDate } from '@kerf-js/veneer'export function Hours() {  return (  <TimeField    label="Deploy window opens"    hint="Office hours"    today={TODAY}    defaultValue="10:00"    min="08:00"    max="18:00"    step={60}  />  )}const min = 60_000const TODAY: IsoDate = '2026-11-02'

When the clocks change

With date and timeZone, a time that happens twice or not at all gets a hint.

tsx
import { TimeField } from '@kerf-js/veneer'import type { IsoDate } from '@kerf-js/veneer'export function ClocksChange() {  return (  <TimeField    label="Nightly backup"    today={TODAY}    defaultValue="01:30"    date="2026-11-01"    timeZone="America/New_York"  />  )}const TODAY: IsoDate = '2026-11-02'

Quiet hours

Use step to set how many minutes apart the times are, here 30.

tsx
import { state } from '@kerf-js/core'import {  Row,  Stack,  Text,  TimeField} from '@kerf-js/veneer'import type { IsoDate, IsoTime } from '@kerf-js/veneer'export function QuietHours() {  const from = state<IsoTime | null>('22:00')  const to = state<IsoTime | null>('07:30')  return (    <Stack gap="related">      <Row        gap="related"        wrap={false}      >        <TimeField          label="Quiet from"          today={TODAY}          value={from}          step={30}        />        <TimeField          label="Until"          today={TODAY}          value={to}          step={30}        />      </Row>      <Text        subtle        role="caption"      >        No alerts from {from.value ?? '…'} to{' '}        {to.value ?? '…'}, except failed deploys.      </Text>    </Stack>  )}const TODAY: IsoDate = '2026-11-02'

Accessibility

Up/Down
Changes the hour or minute
Arrowsinthelist
Move through the times
Enter
Picks the time
Escape
Closes the list

Theming

Restyle it app-wide from veneer() in your kerf config. Every key takes colour, spacing, size, radius, shadow, type and motion; its own keys are listed. A state nests inside: hover: { bg: 'ink' }. Text on a fill you set is contrast-checked at build. How theming works

KeyOwn keysStates
parts.fieldbg, radiushover, focus, press, active, open, disabled
parts.field.labeltexthover, focus
ts
veneer({  colors: { brand: '#e8590c', ink: '#1b1b1f' },  parts: {    field: { radius: 4, label: { focus: { text: 'brand' } } },  },})

API Reference

PropTypeDefaultDescription
labelstring—The accessible name, drawn as the floating border label (or above, classic). Required.
hintunknown—One line of help under the control.
errorunknown—Shown instead of the hint; marks the field invalid.
iconIconRef—Leading icon: it sweeps with the border.
prefixunknown—Text or an element inside the field before the value, such as $.
suffixunknown—Text or an element inside the field after the value, such as kg.
variant"floating" | "classic"—floating (default, or the app's veneer({ fields })) · classic: the label above.
appearance"line"—line: only a bottom line under the value, no box or fill. The boxed field otherwise.
size"sm" | "md" | "lg"'md'Control size. md by default.
clearablebooleanfalseA clear button (shown once there is a value).
counternumber—Maximum length, shown as a counter.
idstring—The element id. One is made for you if you leave it out.
disabledbooleanfalseTurns it off, and takes it out of the tab order.
readonlybooleanfalseShows the value and lets it be selected and copied, but not changed.
requiredbooleanfalseThe form will not submit without it.
namestring—The name it posts under in a form.
localestring—The language and region used to format values.
todaystring—Pins "today" (server render, tests); the browser's clock otherwise.
presentationPresentation—auto opens a popover, or a sheet when the viewport is under 600px wide; popover and sheet force one.
valueIsoTime | State<IsoTime | null> | null—The current value, when you own the state.
defaultValueIsoTime | null—The starting value, when the component owns the state.
openboolean | State<boolean>—A state box that holds whether it is open.
defaultOpenbooleanfalseStarts open, when the component keeps its own open state.
hourCycle"auto" | "h12" | "h23"—h12 shows AM and PM, h23 a 24-hour clock, auto the locale's.
stepnumber15Minutes between listed times.
secondsbooleanfalseAdds a seconds segment.
minIsoTime—The lowest allowed value.
maxIsoTime—The highest allowed value.
slotsIsoTime[]—The exact times to list.
date`${number}-${number}-${number}`—Only for the daylight saving hint.
timeZonestring—Only for the daylight saving hint.
EventTypeDefaultDescription
onInput((e: InputEvent & { currentTarget: HTMLInputElement & HTMLTextAreaElemen…—Called on each keystroke.
onValueChange((v: IsoTime | null, reason: ChangeReason) => void)—Called with each new value, and whether a pointer, a key or code made the change.
onOpenChange((o: boolean) => void)—Called with true when it opens and false when it closes.

RelatedDate time fieldDuration field