Forms
TimePicker
A fully accessible time-only picker with popup spinbuttons (hour/minute/optional second), direct text input, min/max and step support. Follows W3C ARIA Spinbutton pattern. Use for appointment times, business hours, and any time-of-day field. Consistent with DatePicker styling and behavior.
Basic (24-hour)
Default 24-hour format. Value is stored as HH:mm. Type in the field or click the clock to open the popup. Use arrow keys in the popup to change hour and minute; Tab to move between segments.
TimePicker in a Modal
Click the button to open a modal containing a TimePicker. The modal uses scrollBehavior outside so the time popup is not clipped. Useful for scheduling flows.
Date + Time in a small dialog
Both DatePicker and TimePicker side by side in a small modal—e.g. for scheduling. Uses a constrained grid so neither overflows; calendar and time popups use scrollBehavior outside so they are not clipped.
12-hour format
Display and input in 12h with AM/PM. Value is still stored as 24h (e.g. 2:30 PM → 14:30). Type the time and include AM or PM.
Appointment time (15-minute step)
Minute step in 15-minute increments (0, 15, 30, 45). Ideal for appointment slots. When opening the popup, minutes snap to the nearest step.
Business hours (min / max)
Constrain selectable time to a range (e.g. 09:00–17:00). Combined with step for clean slot selection.
With seconds
Include seconds in value and in the popup. Value format is HH:mm:ss. Use for exact timestamps or duration start/end.
Date of Service time with validation
Example: time of service must be within 08:00–18:00. Error is set from outside based on value.
Date formats (24h vs 12h)
Same value displayed in 24h and 12h formats.
Sizes
Choose appropriate sizes based on form density.
Validation states
Shows error and success states for form validation.
Disabled & read-only
Use disabled for unavailable fields and read-only for view-only data.
Clearable with success message
Optional field with clear button and success message when set.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | Unique identifier for the input (auto-generated if not set) |
name | string | — | Form field name |
label * | string | — | Input label text |
value | string | '' | Time string (HH:mm or HH:mm:ss, 24h) - bindable |
format | '12h' | '24h' | '24h' | Display format (12h shows AM/PM) |
placeholder | string | — | Placeholder (defaults to format hint) |
required | boolean | false | Marks field as required |
disabled | boolean | false | Disables the input |
readonly | boolean | false | Makes input read-only |
error | string | — | Error message to display |
hint | string | — | Helper text shown on focus |
successMessage | string | — | Success message when valid |
size | 'sm' | 'md' | 'lg' | 'md' | Input size |
iconLeft | Snippet | — | Icon to display on the left |
hideLabel | boolean | false | Hide label visually (still accessible) |
class | string | — | Additional CSS classes for the wrapper |
stepMinutes | number | 1 | Minute step in popup (e.g. 1, 5, 15, 30) |
showSeconds | boolean | false | Include seconds in value and popup |
minTime | string | — | Minimum time (HH:mm or HH:mm:ss) |
maxTime | string | — | Maximum time (HH:mm or HH:mm:ss) |
clearable | boolean | false | Show clear button |
validateOnMount | boolean | false | Show validation state immediately |
onchange | (value: string, time: TimeValue | null) => void | — | Called when value changes |
onopen | () => void | — | Called when popup opens |
onclose | () => void | — | Called when popup closes |
onclear | () => void | — | Called when clear button is clicked |
testId | string | — | Test ID for e2e testing |
alwaysShowFooter | boolean | false | When true, the message footer is always rendered with reserved space to prevent layout shift when hint/error appears. |
Keyboard & popup
Focus the input and press Alt + ↓ to open the time picker. Inside the popup, each segment (hour, minute, optional second) is a spinbutton. Use Tab to move between segments; Enter from a spinbutton applies the time and closes the popup. Escape closes without applying. Focus is trapped in the popup and returns to the trigger when closed.
| Key | Action |
|---|---|
| Alt + ↓ | Open time picker popup |
| Tab / Shift+Tab | Move between segments and buttons (focus trapped in popup) |
| Enter | When focus is on a spinbutton: apply time and close. On OK: confirm. On Cancel: close without applying. |
| Escape | Close popup (focus returns to trigger) |
| ↑ / ↓ | Increase / decrease value for focused segment |
| Home / End | Min / max value for focused segment |
| Page Up / Page Down | Larger step (e.g. +10 / −10 minutes) |
Message footer & layout shift
The message footer (hint, error, success) is shown in a reserved area below the input. To avoid layout shift when content appears or changes (e.g. hint on focus, error when validation runs), the footer is rendered whenever the component can show any of that content—even if nothing is visible yet. When there is nothing to display, an invisible placeholder reserves one line of space.
- Default: Footer is shown when the component has a hint, error, or successMessage. Footer is hidden only when none of these are set.
- alwaysShowFooter: Set to
trueto always reserve footer space (e.g. when your app sets hint or error dynamically).
Usage tips
- • Use stepMinutes (5, 15, 30) for appointment or slot selection to keep values consistent.
- • Use minTime / maxTime for business hours, operating hours, or allowed windows.
- • Use format="12h" when your users expect AM/PM; value is still stored in 24h.
- • Use showSeconds only when exact seconds matter (e.g. timestamps, duration).
- • Combine with DatePicker for date-time (e.g. appointment date + time).
- • Use clearable for optional time fields so users can reset easily.
- • Provide a clear label and hint for context (e.g. "Appointment time", "Business hours 9–5").
Accessibility features
- • WAI-ARIA Spinbutton pattern: Hour, minute, and second segments use
role="spinbutton"witharia-valuenow,aria-valuemin,aria-valuemax,aria-valuetext, andaria-labelledby - • Dialog: Popup uses
role="dialog",aria-modal="true", andaria-label="Choose time" - • Keyboard: Full support for arrows, Home/End, Page Up/Down per segment; Tab/Shift+Tab between segments and buttons; Enter to apply from spinbutton or OK; Escape to close
- • Focus trap: Tab cycles within the popup when open; focus cannot leave the dialog until it is closed
- • Focus restoration: When the popup closes (Escape, OK, Cancel, or outside click), focus returns to the trigger button via the focus trap
- • Focus visible: Spinbuttons and buttons use
:focus-visibleso the focus ring appears for keyboard users, not on mouse click - • Live announcements: Open, select, and clear actions are announced to screen readers via a live region
- • Labels: Each spinbutton is labelled (Hour, Minute, Second) via
aria-labelledby; Cancel and OK buttons havearia-label - • Reduced motion: Popup animation is disabled when
prefers-reduced-motion: reduce
Value format
The value prop always uses 24-hour format: HH:mm or HH:mm:ss when showSeconds is true.
Empty string when no value. The format prop only affects how the time is displayed (12h with AM/PM vs 24h).