chengkangzai/filament-mui-date-picker
Filament MUI Date Picker adds a Material UI-style date and time picker field to Filament forms. Enjoy a clean, familiar interface, customizable formats and localization, and quick integration into any resource, page, or form with minimal setup.
This is a Filament form-field package: it swaps Filament's stock date input for a Material UI (MUI) date picker rendered through a small JS bundle. You use it exactly like any other field inside a form schema, so there is no new mental model to learn — only a different widget and a different set of keyboard/commit semantics.
Install and expose the assets:
composer require chengkangzai/filament-mui-date-picker
php artisan filament:assets
The second command is not optional. The package ships compiled JS/CSS that Filament must publish into public/; without it the field renders as an empty or broken input. Put both commands in your deploy script and in your local setup docs.
Where to look first:
vendor/chengkangzai/filament-mui-date-picker/ for the field class and any publishable views/config — read the field class before assuming a method exists.app/Filament/ resources: the first thing to convert is a single DatePicker on a low-risk form (e.g. a draft/editor-only resource) so you can compare behaviour side by side with the stock field.First use case: replace one DatePicker::make('published_at') in a Resource form with the MUI field, save a value, reload the record, then repeat while typing rather than clicking. That one loop covers 90% of the integration risk (persistence and commit-on-type).
Straight swap inside a Filament schema. The field is a form component, so it composes with the usual Filament modifiers:
use Chengkangzai\FilamentMuiDatePicker\Forms\Components\MuiDatePicker; // confirm exact FQCN in README
MuiDatePicker::make('published_at')
->label('Publish date')
->required()
->minDate(now()->startOfDay())
->columnSpan(1),
Because it is a normal component, it also works in table filters, action modals, and any custom Livewire form that renders a Filament schema — no special wiring required.
Keep the value a plain date string, cast in the model. Do the parsing in your Eloquent casts ('published_at' => 'date:Y-m-d') rather than reaching into the component's JS state. Treat the field as a Y-m-d string producer and your Livewire tests stay boring.
Deploy hook for asset freshness. After every composer update, run php artisan filament:assets. In CI/deploy:
composer install --no-dev --optimize-autoloader
php artisan filament:assets
php artisan optimize
Test strategy split in two. Livewire/Filament tests can assert the value is set and ->assertFormSet()/assertDatabaseHas() after fillForm(). But the interesting behaviour in this release — typing while the calendar is open, Escape dismiss, Clear — lives in the JS layer and will never be exercised by a Livewire test. If those paths matter to your users, add a browser test (Dusk/Playwright) for: open calendar → Shift+Tab to the input → type a date → Escape → save → assert persisted. That is precisely the regression this version fixed.
Reactive forms. If you key other fields off the date (->live() + afterStateUpdated), be aware the state now only changes on commit (typed value or Clear), not on dismiss — which is the correct behaviour for dependent fields, but means an aborted calendar interaction no longer blanks your dependent fields. Good news, but verify any afterStateUpdated logic that assumed a transient empty value.
Pin ^3.1.1 at minimum. v3.1.0 had a data-loss path: open the calendar, Shift+Tab back to the field, type a date, press Escape → field emptied, nothing saved. If you are on 3.1.0, this is a silent data-loss bug for keyboard users; upgrade is a patch-level, non-breaking change.
Escape no longer clears — only Clear clears. Dismissing the calendar (Escape or click-away) previously reported a momentarily empty value that could get committed. Now an empty value is committed exclusively by the Clear button. Two consequences worth knowing:
Calendar clicks still require a full date. Clicking through the MUI calendar needs the last view — you cannot pick a year and stop there. If a field is genuinely year-granularity (e.g. "model year"), this component is the wrong fit; use a select or a plain text/number input. Typing a full date is always accepted, calendar-open or closed.
Stale assets are the #1 false-bug. "I upgraded but the fix isn't working" is almost always a missing php artisan filament:assets (plus a hard refresh, since browsers cache the hashed-but-same-named bundle). Check the generated file timestamp in public/ before filing anything upstream.
Portal/clipping in modals. MUI pops its calendar into a portal; inside Filament modals, slide-overs, and sticky headers you can hit z-index or overflow clipping. If the calendar is cut off inside an action modal, test the same field on a full-page Resource form first to confirm it's a container issue and not the package — then adjust the wrapping panel's overflow or the modal width rather than patching vendor JS.
Empty-vs-null on required fields. Because dismiss no longer writes an empty value, a previously saved date stays put when a user opens and closes the calendar. If you have custom logic that treats "user interacted with the field" as "user changed the field", it will now over-fire less often — usually what you want, but audit any afterStateUpdated side effects (notifications, slug regeneration) that were quietly relying on the old transient-empty behaviour.
Extension points. Format, min/max bounds, and locale are configured on the field, not through a config file; check the field class for the exact method names before assuming parity with Filament's stock DatePicker. Prefer publishing views/assets only if you must customise styling — published assets are yours to maintain and will drift from upstream on the next release.
How can I help you explore Laravel packages today?