TimePicker
A time picker with dropdown hour/minute/second columns (plus an AM/PM column in 12-hour mode); ↑/↓ adjusts, Home/End jumps to bounds, Enter confirms, Esc cancels. Stepping intervals, disabled times, ranges, and direct typing are supported.
Basic Usage
Basic usage
Manual Input
Type a time (committed on blur / Enter)
Input is parsed as H:mm[:ss] (single digits tolerated, e.g. 9:5); in 12-hour mode an AM/PM word may be appended. Invalid input reverts on blur without touching the value.
Custom Format
format column selection
A column appears only when format contains the corresponding token.
12-Hour Mode
use12-hours (value stays 24-hour)
Display and columns switch to 12-hour (AM/PM words follow the locale); the fourth column toggles AM/PM. The value contract stays HH:mm:ss 24-hour.
Stepping
step minute interval (single number, back-compat)
step JSON triple (hour/minute/second)
step accepts {"h":2,"m":5,"s":1} for per-unit stepping; a single number remains the minute step. Values outside the step set snap to the nearest option visually without changing the value.
Disabled Times
disabledTime (grayed, not hidden)
disabledTime (property, (parts) => { hours?, minutes?, seconds? }) returns disabled lists per current-time context; disabled options are grayed out (clicks and keyboard skip them).
hide-disabled-options (hide disabled options instead of greying)
Used with disabledTime: hide-disabled-options removes disabled options from the columns entirely (default keeps them visible but grayed out) — in this example the current value sits in the closed hours (14–16), so those three entries are hidden from the hour column; keyboard ↑/↓ and nearest-snapping already skip disabled values at the value level, so behavior is unchanged.
Accessible Naming
label: trigger accessible name
label gives the trigger input an accessible name (aria-label, announced by screen readers); it falls back to placeholder when unset. An external <label for> association takes precedence (native label semantics).
Now & Presets
Now button (footer)
The panel footer has a built-in Now button that fills the current time and confirms.
presets quick times (property)
presets (property, an array of { label, value: 'HH:mm:ss' }) renders a button row atop the panel; clicking one applies it and closes the panel.
Timezone (timezone)
timezone anchor: UTC vs local
timezone accepts an IANA zone name (e.g. Asia/Tokyo) or UTC; an omitted/invalid value falls back to the host local zone. The Now button and default-time derivation read the wall clock of the configured zone; the value contract (HH:mm:ss) is unchanged. Open the left panel and click Now for UTC, the right one for the local time; the reference line below shows both zones' current time.
Time Range
is-range (dual column groups, auto order)
With is-range the value is a JSON array; start/end are picked independently and auto-ordered on confirm.
Form States
Sizes
Status & clearable
Readonly
Under readonly the panel still opens for browsing, but picking, Now, presets, clearing, and typing never commit.
Controlled Open & Events
oas-change / oas-confirm events
Controlled open (open + oas-open-change)
With the open attribute present the picker runs in controlled mode: gestures only emit oas-open-change, and opening/closing is decided by the host adding or removing the attribute; confirm actions (Enter, outside click, Now) emit oas-confirm alongside oas-change.
Disabled
Disabled
Floating Positioning (placement)
Explicit placement (top-end)
Same positioning contract as date-picker: fixed + collision flipping + viewport clamping; the panel width matches the trigger. 12 directions (default bottom-start).
Mobile form (bottom sheet)
On touch screens (coarse pointer) or narrow viewports (<768px), the panel is automatically hosted by an oas-bottom-sheet bottom sheet: rises from the viewport bottom + backdrop + drag handle swipe-down to close (backdrop click / Esc also close), with bottom safe-area inset; the hour/minute/second columns (including the dual-column range layout) scroll inside the sheet; the desktop form keeps the original floating dropdown. Inside the sheet, time option rows are lifted to a 44px touch target (--oas-touch-target-min).
required
required (native validation chain)
required drives the native validation chain (form-associated): when unfilled, checkValidity() returns false (valueMissing) and native form submission is blocked; it recovers to :valid once filled.
Programmatic read/write of the current value goes through the public value property: el.value reads the raw value attribute in single mode, or an array of start/end time strings in is-range mode (same shape as the oas-change detail); el.value = x writes the controlled value attribute and immediately syncs the trigger (arrays for range mode are JSON-serialized automatically, empty values remove the attribute). No events are dispatched.
API
oas-time-picker
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
clearable | Clearable: shows a clear button when a value exists; emits oas-clear + oas-change (empty value) | boolean | — |
disabled | Disabled | boolean | — |
format | Display format tokens; a column appears only when the corresponding token exists | string | HH:mm:ss |
hide-disabled-options | Hide disabled options instead of graying them out (keyboard navigation still skips them) | boolean | — |
is-range | Time range: value is a JSON array ["HH:mm:ss","HH:mm:ss"], auto-ordered on confirm; the typing channel is read-only in this mode | boolean | — |
label | Accessible name (aria-label) for the trigger; an external label-for association takes precedence | string | — |
name | Form field name (key for native FormData submission; range mode derives name-start / name-end entries; the browser skips submission when name is absent) | string | — |
open | Controlled open: present = open, removed = closed; gestures only emit oas-open-change for the host to write back; in the mobile form (touch / viewport <768px) the open panel is hosted by an oas-bottom-sheet bottom sheet (swipe-down/backdrop/Esc to close); desktop keeps the floating dropdown | — | — |
placeholder | Placeholder text | — | — |
placement | Popup placement, 12 directions (default bottom-start), fixed + collision flipping + viewport clamping (same contract as date-picker) | string | bottom-start |
readonly | Readonly: the panel can be opened and browsed, but no interaction commits | boolean | — |
required | Required marker (drives the native valueMissing validation chain; not passed through to the inner control) | boolean | — |
size | Size: small / medium / large (reads the nearest config-provider injection) | string | medium |
status | Validation status: success / warning / error (error also sets aria-invalid) | string | — |
step | Stepping: a JSON triple {"h":2,"m":5,"s":1} per unit; a single number remains the minute step | string | — |
timezone | Timezone anchor: an IANA zone name or UTC; omitted/invalid falls back to local. The Now button and default-value derivation read this zone's wall clock; the value contract is unchanged | string | — |
use12-hours | 12-hour mode: display and columns switch to 12-hour (with an AM/PM column following the locale); the value stays 24-hour | boolean | — |
value | Current value (HH:mm:ss; a JSON array when is-range) | string | string[] | null | — |
Property (JS property; see each row for attribute reflection)
| Property | Description | Type | Default |
|---|---|---|---|
disabledTime | Disabled-time predicate (property function channel, (parts) => { hours?, minutes?, seconds? }) | | ((parts: TimeParts) => { hours?: number[]; minutes?: number[]; seconds?: number[] } | null) | null | — |
presets | Quick time presets (property channel, [{ label, value }]) | PresetItem[] | null | — |
value | Current value: a time string for single; a string array when is-range | string | string[] | null | — |
Events
| Event | Description |
|---|---|
oas-blur | The component as a whole loses focus (internal moves do not fire) |
oas-change | Confirmed value change, detail: { value } (string array for is-range) |
oas-clear | Clear, detail: { value } is the previous value |
oas-confirm | Emitted on confirm actions (Enter / outside click / Now, alongside oas-change), detail: { value: detail } |
oas-focus | The component as a whole gains focus |
oas-open-change | Open state change, detail: { open } (both controlled and uncontrolled) |
CSS Variables
| CSS Variable | Default |
|---|---|
--oas-glass-blur | none |
--oas-glass-ring | transparent |
Keyboard: Enter / ↓ to open, ↑/↓ to adjust the current column, Home/End to jump to bounds, ←/→ to switch columns, Enter to confirm, Esc to cancel.