PHPackages                             harvirsidhu/filament-timepicker - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. harvirsidhu/filament-timepicker

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

harvirsidhu/filament-timepicker
===============================

A smart, type-ahead time picker field for Filament. Type freely (3p, 330, 3:30 PM) with a filterable, keyboard-navigable suggestion dropdown.

v1.0.1(today)00MITPHPPHP ^8.2

Since Jun 18Pushed todayCompare

[ Source](https://github.com/harvirsidhu/filament-timepicker)[ Packagist](https://packagist.org/packages/harvirsidhu/filament-timepicker)[ Docs](https://github.com/harvirsidhu/filament-timepicker)[ RSS](/packages/harvirsidhu-filament-timepicker/feed)WikiDiscussions master Synced today

READMEChangelog (2)Dependencies (11)Versions (3)Used By (0)

Filament Smart Time Picker
==========================

[](#filament-smart-time-picker)

A **smart, type-ahead time field for [Filament](https://filamentphp.com)**. Your users just type — `3p`, `330`, `3:30 PM`, `1530` — and a filterable, keyboard-navigable dropdown suggests times at whatever interval you choose. It looks and feels exactly like a native Filament field, but it's far more forgiving for non-technical staff.

```
use Harvirsidhu\FilamentTimepicker\SmartTimePicker;

SmartTimePicker::make('start_time')
    ->label('Start time')
    ->interval(15);
```

---

Why this exists
---------------

[](#why-this-exists)

The native `TimePicker` is either a clumsy browser control or a spinner you have to nudge digit by digit. People who book appointments all day want to type `9` and move on. This field gives them that, while still storing a clean, canonical value.

You typeIt storesIt shows`9``09:00`9:00 AM`3p``15:00`3:00 PM`330``03:30`3:30 AM`1530``15:30`3:30 PM`3:30 PM``15:30`3:30 PM`9.30` / `9h30``09:30`9:30 AMThe `hh:mm` part accepts a colon, a dot, or an `h` as the separator — so `9:30`, `9.30`(UK/Malaysia) and `9h30` (French) all work. Anything unparseable is rejected on the server, so bad data never reaches your database.

---

Features
--------

[](#features)

- ⌨️ **Forgiving free-text input** — meridiems (`3p`, `3 pm`), bare hours (`9`), compact digits (`330`, `1530`), and `:`/`.`/`h` separators (`9.30`, `9h30`) all parse to a canonical 24-hour value.
- 📋 **Suggestion dropdown** at a configurable `interval`, filtered as you type.
- 🔒 **Optional `strict` mode** — confine values to the interval grid, with a validation error for anything off it.
- 🧭 **Full keyboard control** — ↑/↓ to move, Enter/Tab to pick, Esc to close.
- ⏱️ **Relative duration hints** — show `30 mins`, `1 hour 15 mins` next to each option, perfect for an "end time" that depends on a "start time".
- 🕒 **Min / max bounds** — only offer times inside a window (e.g. opening hours).
- 🌍 **Wall-clock safe** — a 3 PM slot is always `15:00`; no surprise timezone shifts.
- 🎨 **Native Filament look** — built on the same input chrome, light/dark aware.
- 🪶 **Lazy-loaded JS** — the Alpine component only downloads when a field is on the page.

---

Installation
------------

[](#installation)

```
composer require harvirsidhu/filament-timepicker
```

Publish the component's assets (this copies the lazy-loaded JS into `/public`):

```
php artisan filament:assets
```

If you use a [custom Filament theme](https://filamentphp.com/docs/5.x/themes), register the package's views so Tailwind compiles the dropdown styles. Add this to your theme's `resources/css/filament//theme.css`:

```
@source '../../../../vendor/harvirsidhu/filament-timepicker/resources/views/**/*.blade.php';
```

Then rebuild your theme: `npm run build`.

> **Requirements:** PHP 8.2+, Filament v4 or v5.

---

Usage
-----

[](#usage)

### The basics

[](#the-basics)

```
use Harvirsidhu\FilamentTimepicker\SmartTimePicker;

SmartTimePicker::make('start_time')
    ->label('Start time')
    ->interval(15)              // dropdown every 15 minutes (default)
    ->required();
```

The value is stored as a `H:i` string (e.g. `"15:30"`) — drop it straight into a `time`column.

### Restrict to a window (e.g. opening hours)

[](#restrict-to-a-window-eg-opening-hours)

```
SmartTimePicker::make('start_time')
    ->minTime('09:00')
    ->maxTime('18:00')
    ->interval(30);
```

`minTime` / `maxTime` accept a string, a `Carbon` instance, or a closure:

```
SmartTimePicker::make('start_time')
    ->minTime(fn (Get $get) => $get('opens_at'));
```

### Start &amp; end times, with live duration labels

[](#start--end-times-with-live-duration-labels)

Point an "end time" at its "start time" with `relativeTo()`. The dropdown then only offers times *after* the start and labels each one with how long the appointment would run:

```
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Components\Utilities\Set;

SmartTimePicker::make('start_time')
    ->live()
    ->afterStateUpdated(function (Get $get, Set $set) {
        // optionally precompute an end time, etc.
    }),

SmartTimePicker::make('end_time')
    ->relativeTo('start_time'),   // shows "30 mins", "1 hour", "1 hour 15 mins" …
```

`relativeTo()` resolves the sibling field automatically, even inside repeaters and nested groups — pass the field's name, not its full path.

### Seconds

[](#seconds)

```
SmartTimePicker::make('alarm_at')
    ->seconds()                 // stores/displays "H:i:s"
    ->interval(1);
```

### Display format

[](#display-format)

The displayed text uses [PHP `date()` tokens](https://www.php.net/manual/en/datetime.format.php). The default is `g:i A` (non-padded, e.g. *3:30 PM*):

```
SmartTimePicker::make('start_time')->displayFormat('h:i A');  // 03:30 PM
SmartTimePicker::make('start_time')->displayFormat('H:i');    // 15:30 (24-hour)
```

### Strict mode

[](#strict-mode)

By default the field is forgiving: a user can type any valid time (e.g. `12:01`) even if it isn't one of the suggested slots. Call `strict()` to confine values to the interval grid:

```
SmartTimePicker::make('start_time')
    ->interval(15)
    ->strict();   // only :00, :15, :30, :45 (within min/max) are accepted
```

With `strict` on, typing an off-grid time snaps the box back to the last valid value as you go, and any off-grid value that reaches the server (a pasted entry, a programmatic default, an import) fails validation with a clear message rather than being silently dropped. Leave it off (the default) to keep the loose, type-anything behaviour.

---

API reference
-------------

[](#api-reference)

MethodDefaultDescription`interval(int|Closure)``15`Minutes between dropdown suggestions.`minTime(string|Carbon|Closure|null)``null`Earliest selectable time (inclusive).`maxTime(string|Carbon|Closure|null)``null`Latest selectable time (inclusive).`relativeTo(string|Closure|null)``null`Sibling field name; adds duration labels and a floor.`displayFormat(string|Closure)``'g:i A'`How the value is shown, in PHP `date()` tokens.`seconds(bool|Closure)``false`Store/display seconds (`H:i:s`).`strict(bool|Closure)``false`Confine values to the interval grid; off-grid times fail validation.It also accepts `native()` and `timezone()` as **no-ops**, so it's a drop-in replacement for Filament's `TimePicker` — existing call chains keep working.

### Drop-in migration

[](#drop-in-migration)

```
- use Filament\Forms\Components\TimePicker;
+ use Harvirsidhu\FilamentTimepicker\SmartTimePicker;

- TimePicker::make('start_time')
+ SmartTimePicker::make('start_time')
      ->seconds(false)
      ->native(false)        // ignored, but harmless
      ->required();
```

### Parsing outside the field

[](#parsing-outside-the-field)

The parser is a plain, dependency-free class you can reuse anywhere (validation, imports, APIs):

```
use Harvirsidhu\FilamentTimepicker\Support\TimeParser;

TimeParser::parse('3:30 pm');   // "15:30"
TimeParser::parse('930');       // "09:30"
TimeParser::parse('9.30');      // "09:30"  (dot / "h" separators too)
TimeParser::parse('nope');      // null
TimeParser::format('15:30');    // "3:30 PM"
```

---

How it works (for the curious)
------------------------------

[](#how-it-works-for-the-curious)

- The visible text box is driven by a **local Alpine string**, never bound directly to Livewire. The canonical `H:i` value is written to the entangled state only when you *commit* (pick an option, press Enter, or blur with valid text). Typing never round-trips half-parsed text through the server, so your cursor never jumps.
- Parsing happens in **two places that mirror each other**: instantly in JS for feedback, and authoritatively in PHP (`TimeParser`) on dehydration. The server always has the final say, so a value is either clean `H:i`/`H:i:s` or `null`.
- The Alpine component is shipped as a Filament asset and **lazy-loaded with `x-load`**, so it costs nothing on pages that don't use it.

---

Development
-----------

[](#development)

```
composer install
npm install

npm run dev      # watch + rebuild the Alpine component
npm run build    # production build into resources/js/dist
composer test    # Pest test suite
```

After changing the JS, consuming apps must re-run `php artisan filament:assets`.

---

Credits
-------

[](#credits)

- [harvirsidhu](https://github.com/harvirsidhu)

License
-------

[](#license)

The MIT License (MIT). See [LICENSE.md](LICENSE.md).

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/7453102?v=4)[harvirsidhu](/maintainers/harvirsidhu)[@harvirsidhu](https://github.com/harvirsidhu)

---

Top Contributors

[![harvirsidhu](https://avatars.githubusercontent.com/u/7453102?v=4)](https://github.com/harvirsidhu "harvirsidhu (10 commits)")

---

Tags

laraveltimetimepickerfilamentfilament-pluginfilamentphpharvirsidhufilament-timepickerform-fieldtime picker

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/harvirsidhu-filament-timepicker/health.svg)

```
[![Health](https://phpackages.com/badges/harvirsidhu-filament-timepicker/health.svg)](https://phpackages.com/packages/harvirsidhu-filament-timepicker)
```

###  Alternatives

[dotswan/filament-map-picker

Easily pick and retrieve geo-coordinates using a map-based interface in your Filament applications.

128173.7k3](/packages/dotswan-filament-map-picker)[jibaymcs/filament-tour

Bring the power of DriverJs to your Filament panels and start a tour !

12351.0k](/packages/jibaymcs-filament-tour)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3913.7k](/packages/rawilk-profile-filament-plugin)[wsmallnews/filament-nestedset

Filament nestedset tree builder powered by kalnoy/nestedset with Filament v4 and v5 support

196.5k14](/packages/wsmallnews-filament-nestedset)[marcelweidum/filament-passkeys

Use passkeys in your filamentphp app

6643.3k1](/packages/marcelweidum-filament-passkeys)[hammadzafar05/mobile-bottom-nav

A thumb-friendly mobile bottom navigation bar for Filament panels. It programmatically integrates with the Filament navigation registry to provide a seamless, ergonomic mobile experience with full support for dark mode and safe-area insets.

1812.3k](/packages/hammadzafar05-mobile-bottom-nav)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
