Native Time Picker for NativePHP#
A truly native scrolling-wheel time picker for NativePHP Mobile apps. Instead of relying on the OS system dialog (which iOS/Android skins render inconsistently), this plugin draws its own wheel-picker dialog with Jetpack Compose on Android and SwiftUI on iOS — so the picker looks and feels identical on every device, in both light and dark mode.
Features#
- 🎡 Custom scrolling-wheel dialog — no dependency on the stock Android/iOS time picker
- 🕒 12h (AM/PM) or 24h display mode, independent of the wire value format
- 🎨 Theming via
accent-color, falls back to your app's native theme - ♿️ Accessibility labels/hints out of the box
- 🔌 Simple wire format: the value is always a zero-padded 24h
HH:mmstring - 📱 iOS 15+ and Android API 21+
Requirements#
| Version | |
|---|---|
| PHP | ^8.2 |
| nativephp/mobile | * |
| iOS | 15.0+ |
| Android | API 21+ |
Installation#
Since this plugin isn't (yet) published on Packagist, add it as a path repository in your NativePHP app's composer.json:
{ "repositories": [ { "type": "path", "url": "../nativephp-timepicker" } ]}
Then require it:
composer require nativecodeforge/nativephp-timepicker
NativePHP requires you to explicitly opt in to every plugin's native code before it's built into your app:
php artisan native:plugin:register NativeCodeForge/nativephp-timepicker
Rebuild the native projects so the manifest (renderers, min SDK versions, etc.) is picked up:
php artisan native:install --force
Quick start#
<native:time-picker label="Appointment time" placeholder="Select a time" wire:model="appointmentTime"/>
use Livewire\Component; class BookingForm extends Component{ public string $appointmentTime = ''; public function save(): void { // $this->appointmentTime is always a zero-padded 24h "HH:mm" string }}
That's it — tapping the field opens the native wheel-picker dialog; the confirmed time is written back to the bound Livewire property as HH:mm.
Attributes#
| Attribute | Type | Default | Description |
|---|---|---|---|
value |
string |
— | Zero-padded 24h time (HH:mm) to show as selected. Usually set via wire:model instead. |
label |
string |
— | Field label shown above/inside the input. |
placeholder |
string |
— | Placeholder text shown when no time is selected. |
disabled |
bool |
false |
Disables the field. |
is24hour |
bool |
true |
Controls the dialog's own display mode (AM/PM vs 24h). The wire value is always 24h HH:mm regardless of this setting. |
title |
string |
"Set time" |
Title shown at the top of the picker dialog. |
cancel-label |
string |
"Cancel" |
Label of the dialog's cancel button. |
confirm-label |
string |
"Done" |
Label of the dialog's confirm button. |
now-label |
string |
— | When set, shows a button that jumps the wheel to the current hour/minute. |
accent-color |
string |
theme primary | Hex color (#RRGGBB or #AARRGGBB) overriding the accent color for this picker only. |
a11y-label |
string |
— | Accessibility label (screen readers). |
a11y-hint |
string |
— | Accessibility hint (screen readers). |
All attributes are also available in camelCase (e.g. cancelLabel, is24Hour) when building elements programmatically.
Events#
Bind wire:model for two-way binding, or listen for changes explicitly with wire:change:
<native:time-picker label="Start time" wire:model="startTime" wire:change="onStartTimeChanged($event)"/>
The value sent to the handler (and stored in the bound property) is always a zero-padded 24h HH:mm string, regardless of the device's locale or is24hour display setting — so PHP-side parsing (Carbon::createFromFormat('H:i', $value)) stays consistent across platforms.
Programmatic usage#
For advanced cases (e.g. building the element dynamically), use the underlying Element class directly:
use NativeCodeForge\NativeTimePicker\Elements\TimePicker; TimePicker::make() ->value('14:30') ->label('Appointment time') ->title('Choose a time') ->is24Hour(false) ->nowLabel('Now') ->accentColor('#6C5CE7') ->onChange('onAppointmentTimeChanged');
Theming#
accent-color overrides the border/label/selected-wheel-row color for this picker instance only, without touching your app's global theme.
Accessibility#
Set a11y-label and a11y-hint to give screen readers a meaningful description of the field and what happens on activation — both map directly to accessibilityLabel/contentDescription and accessibilityHint/stateDescription on iOS/Android respectively.
Screenshots#

Wheel picker dialog on Android (Compose). The iOS counterpart (SwiftUI) renders the same layout with the platform's native styling.

Wheel picker shown here in dark mode.
License#
Proprietary — see LICENSE.md. Licensed via the NativePHP Marketplace.