Time Picker
The <x-wirekit::time-picker> component is a styled wrapper around the native <input type="time">. It uses the browser's built-in time selection UI for zero dependencies and automatic localization.
Basic Usage
12-Hour Format
The format prop controls the visual display. Regardless of format, the submitted value is always in 24-hour HH:MM format (the native <input type="time"> standard).
Note: The 12-hour vs 24-hour display is ultimately controlled by the browser and OS locale. The
formatprop provides a hint but browsers may override it.
With Step (Minutes Interval)
Available in 15-minute intervals
The step attribute is in seconds. Common values: 60 (1 min), 300 (5 min), 900 (15 min), 1800 (30 min), 3600 (1 hour).
Size Variants
Error State
Please select a valid time.
With Hint
We will notify you at this time daily.
Width
Like all WireKit form components, the time picker fills its container (w-full). Time fields are typically narrow — constrain the width via the parent element:
<div class="max-w-[10rem]">
<x-wirekit::time-picker label="Start time" name="start_time" />
</div>
See Input — Width for more layout examples (grid columns, mixed widths).
Why Native?
The native <input type="time"> provides:
- Zero dependencies — no JavaScript time picker library to ship
- Automatic localization — the browser renders AM/PM or 24-hour based on OS locale
- Full accessibility — arrow keys, spinners, and keyboard input work out of the box
- Mobile keyboards — native time wheels on iOS, spinners on Android
- Consistent value format — always
HH:MMregardless of display
Optimistic UI
Pass the name of the Livewire method this component should call and the change appears immediately, then confirms or undoes itself when the server answers:
<x-wirekit::time-picker
name="start"
:value="$start"
optimistic="setStart"
/>
Load wirekit-optimistic.js alongside whichever bundle you already use — it is a separate file so applications that do not use it pay nothing for it:
@wirekitScripts
<script src="{{ asset('vendor/wirekit/wirekit-optimistic.js') }}"></script>
Try it
The demo below runs the real path: the change shows immediately, the outline says it is provisional, and the server's answer either confirms it silently or takes it back.
The <livewire:demos.…> wrapper above exists only on this site — it supplies the demo
methods so the page can show a real round trip. The block under it is what you write.
The same shape as the other native form controls: the browser has already changed the value by the time any handler runs, so what this adds is the confirmation, the undo, and the announcement.
What a screen reader hears is the same for every component that supports this, and it is written out in full — one hedged announcement at the change, silence on confirmation, one more only if the server refuses, and focus that never moves — in Optimistic UI — the announcement contract. That page is also where the boundary is stated: this covers mutations, not sorting, filtering or pagination.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
optimistic |
string|null |
null |
Livewire method to call, showing the new value before the server confirms it. See Optimistic UI. |
optimisticArgs |
array |
[] |
Extra arguments appended to the optimistic action call, after the new value — the row this control belongs to. |
label |
string|null |
null |
Label text above the input |
hint |
string|null |
null |
Help text below the input |
error |
string|null |
null |
Error message (also reads from $errors) |
name |
string|null |
null |
Form field name |
id |
string|null |
auto-generated | Element id |
value |
string|null |
null |
Initial time in HH:MM format |
format |
string |
'24h' |
'24h' or '12h' (display hint) |
step |
int|null |
null |
Step interval in seconds |
size |
string |
'md' |
'sm', 'md', 'lg' |
disabled |
bool |
false |
Disabled state |
required |
bool |
false |
Required field |
scope |
string|null |
null |
Scoped personalization key |
Accessibility
- Native
<input type="time">— full browser a11y and keyboard support aria-invalid="true"andaria-describedbyset on erroraria-required="true"when required- Hint text linked via
aria-describedby - Focus ring visible via
focus-visiblestyling - Arrow keys increment/decrement hours and minutes (native behavior)
- The value is always submitted in ISO
HH:MMformat regardless of locale display
Keyboard Interaction
| Key | Action |
|---|---|
Tab |
Move focus into the time input |
Type HH:MM characters |
Set the value directly |
ArrowUp / ArrowDown |
Step the focused field by ±1 |
Pitfalls
- Don't use time-picker for durations. Native
<input type="time">represents a clock time, not "2 hours 30 minutes". For durations use two<x-wirekit::number-input>(hours / minutes).
Design Tokens
| Token | Purpose |
|---|---|
--color-wk-bg-input |
Input background |
--color-wk-border-strong |
Default border color |
--color-wk-border-error |
Border color on error |
--color-wk-text |
Input text color |
--color-wk-text-placeholder |
Placeholder text color |
--color-wk-ring |
Focus ring color |
--size-wk-sm / md / lg |
Input height per size variant |
--radius-wk-md |
Border radius |
--padding-wk-x-md |
Horizontal padding |
--text-wk-md |
Font size |
--transition-wk-duration |
Focus/error transition speed |
--opacity-wk-disabled |
Dimmed state when disabled |
Customization
Override defaults in config/wirekit.php:
'components' => [
'time-picker' => ['size' => 'md', 'format' => '24h'],
],
Further Reading
- MDN:
<input type="time"> - MDN: Date and time input types
- Can I Use:
input type=time— browser support matrix - MDN:
stepattribute - MDN:
aria-invalid