malzariey/filament-daterangepicker-filter
Native Alpine.js date range picker and filter for Filament with day, month, and year modes, presets, optional time selection, keyboard input, localization, and modal/slide-over compatibility. Includes drop-in DateRangePicker field and DateRangeFilter.
composer require plus a fluent field definition. The decision it supports is: do we spend engineering weeks on a solved UI primitive, or on the reporting features that sit on top of it?->ranges([...])), defaultLast7Days(), defaultThisMonth(), and useRangeLabels() turn "give users a date filter" into a concrete, demoable slice. It supports committing to reporting work in a roadmap without a design-plus-frontend dependency.monthPicker() and yearPicker() support genuinely different products: billing periods (m/Y), fiscal-year reporting (Y), and subscription/cohort windows. Without these, finance-adjacent requests get deferred or hacked into text fields.maxSpan(['months' => 1]), disableCustomRange(), and curated ranges() are levers a PM can use to bound expensive report queries and steer users toward the windows the product actually supports — a UX decision, not an infra one.FilamentTimezone) from storage timezone (config('app.timezone')). Before that, any app that set a display timezone silently mis-bucketed rows in the first hours of a local day. PM-relevant: date filters that are quietly wrong are worse than no date filter, because they erode trust in every number on the screen. If your product shows local times over UTC storage, this release is a correctness requirement, not a nice-to-have.displayFormat() → format(), jQuery/Moment.js removed in favor of Alpine/Day.js). That makes the cost of staying on an older Filament auditable rather than open-ended.Adopt when most of these hold:
useDualState('start_date', 'end_date') to bind separate Livewire properties), modal/slide-over compatibility, or timezone-aware filtering over UTC storage.modifyQueryUsing() on the filter covers cases the default whereBetween doesn't.Look elsewhere, or budget explicitly for ownership, when:
To executives: We can ship date-range filtering across reporting screens in days instead of weeks, with no licensing cost (MIT). It delivers the things users actually ask for — "last 30 days," "this month," billing periods, fiscal years — plus keyboard entry and accessibility that we would otherwise under-invest in. Risk is bounded: it's MIT-licensed, small, and forkable, so the worst case is we own a few hundred lines, not a re-platforming. The recent 5.0.7 release also fixed a timezone bug where filtered reports could silently omit the first hours of a local day — that's a trust issue with dashboard numbers, and it's already fixed for us.
To engineering: Native Filament v4 field and filter, Alpine.js + Day.js (no jQuery/Moment), teleports the dropdown to <body> to survive modal and slide-over z-index stacking. Filters support modifyQueryUsing(fn($query, $start, $end, $raw) => ...) so anything non-standard is a closure, not a fork. Timezone handling now mirrors Filament's own DateTimePicker: getTimezone() for display, getSystemTimezone() for storage, with a systemTimezone() override for columns stored outside the app zone. Dual state lets start and end map to separate Livewire properties. Upgrade path from v3/v4 is documented with an explicit deprecation table.
To design/product: Presets and useRangeLabels() mean users pick "Last 30 Days" instead of doing date math — fewer support tickets and more predictable queries. maxSpan() and disableCustomRange() let us constrain the picker to ranges the product actually supports. Month and year modes cover billing and fiscal reporting without a bespoke UI.
The ask: Timebox a one-resource pilot (roughly a day), validate the timezone configuration against production data — especially if FilamentTimezone::set() is in use — and confirm the package version against our Filament constraint. If the pilot holds, standardize on it for reporting surfaces and delete any bespoke date filters.
How can I help you explore Laravel packages today?