tareq-alqadi/filament-flatpickr
A Filament form field that integrates the Flatpickr date and time picker, making it easy to add lightweight, customizable date, time, and datetime inputs to your admin panels. Install via Composer and configure the picker options directly in your Filament forms.
composer require tareq-alqadi/filament-flatpickr
Before you install, settle the compatibility question — this is the whole story of v5.0.0. The release notes for v5.0.0 are a bare changelog link, so treat it as a breaking major until proven otherwise: open the tag diff (v4.2.0...v5.0.0) and read composer.json for the filament/filament and php constraints. In practice a major bump here tracks a Filament major (v5 targets Filament v4; stay pinned to ^4.2 if you are still on Filament v3). Do not let composer update decide this for you.
Where to look first, in order:
src/Forms/Components/Flatpickr.php — the field class. It is a thin fluent wrapper; every method maps to a flatpickr option. Read it end to end, it is short and it is the real documentation.resources/views/ — the Blade + Alpine wrapper. This tells you which DOM node Livewire binds to and where altInput is injected.resources/js/ — flatpickr initialisation and any bundled plugins/locales. If your option "does nothing", the answer is almost always here or in the asset cache.config/filament-flatpickr.php (publishable) — defaults for locale, format, and asset loading.First use case worth reaching for: replacing Filament's native DateTimePicker on a field where the native picker cannot express the requirement — a date range or a time-only input.
use TareqAlqadi\FilamentFlatpickr\Forms\Components\Flatpickr;
Flatpickr::make('period')
->mode('range')
->dateFormat('Y-m-d')
->displayFormat('d/m/Y'),
After upgrading, always run php artisan filament:assets && php artisan optimize:clear. Stale cached JS is the single most common cause of "the new version behaves like the old one".
Separate stored format from display format. The main day-to-day win over the native picker is altInput: the user sees d/m/Y, Livewire receives Y-m-d. Set both explicitly; never rely on the default.
Flatpickr::make('published_at')
->dateFormat('Y-m-d H:i') // value sent to Livewire / DB
->displayFormat('d M Y, H:i') // what the user sees
->enableTime()
->time_24hr(),
Range and multiple modes produce arrays. Treat the state as array, not a string, all the way through:
Flatpickr::make('booking_window')
->mode('range')
->rule(['array', 'size:2'])
->dehydrateStateUsing(fn (?array $state) => [
'starts_at' => $state[0] ?? null,
'ends_at' => $state[1] ?? null,
]),
For JSON columns, skip the split and cast on the model instead ('booking_window' => 'array'), but then add ->rule('array') — the default rule is date and will fail.
Time-only fields. ->noCalendar()->enableTime()->dateFormat('H:i') bound to a time column. Pair with ->hourIncrement() / ->minuteIncrement() to keep the scroll list short.
Dynamic constraints. Compute bounds from other form state in afterStateHydrated() or a closure if the class exposes one; for disabled dates pulled from a model, resolve the list once outside the field and pass a plain array. Large disabledDates arrays are serialised into the DOM on every render.
Locale per user. ->locale(app()->getLocale()) only works if the matching flatpickr locale bundle is loaded — check the package's registered assets before shipping a non-English admin.
Livewire reactivity. If the field drives dependent fields, add ->live(). Flatpickr writes to the input via JS, so verify the value actually round-trips to Livewire on blur before building logic on top of it.
Testing. fillForm(['published_at' => '2025-01-01T09:00']) bypasses all JS, so it tests your format/normalisation contract but not the widget. Unit-test dehydrateStateUsing and validation; keep browser tests for the picker itself.
Filters. Reuse the exact same format string on the table filter as on the form field, or whereDate comparisons will silently miss rows.
--tag=filament-flatpickr-config --force) rather than carrying your old config across — a silently ignored renamed key looks identical to "the option broke".Y-m-d, H:i) are not PHP's date() tokens and not Filament's format(). Mixing Y-m-d with d/m/Y between dateFormat and validation produces failures that only appear on save, never on render.datetime column will drift by the user's offset. Convert explicitly in dehydrateStateUsing (or via ->timezone()) — do not assume the picker respects config('app.timezone').altInput and programmatic updates. With altInput() there are two inputs; Livewire binds the hidden one. Calling $wire.set() from elsewhere will not re-render the visible box — reset it through the Alpine component or re-key the field.php artisan filament:assets && php artisan optimize:clear, then hard-refresh. Most "options ignored" reports die here.resources/views to your Tailwind content paths or the popup renders unstyled.->options([...]) / individual setters) plus ->extraInputAttributes(); for anything exotic, register a flatpickr plugin in your own JS and pass it by name. Avoid patching the package's Blade view — that is what the v5 upgrade will break.inline() calendars and long disabled-date lists are evaluated per render; on tables with many rows, prefer the modal form or memoise the derived date list.How can I help you explore Laravel packages today?