Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Multiple Date Picker Laravel Package

ghanem/multiple-date-picker

A Laravel/PHP package for adding a multiple-date picker to forms and interfaces, letting users select several dates at once. Useful for scheduling, booking, and date-range scenarios without building multi-date selection logic from scratch.

View on GitHub
Deep Wiki
Context7

Getting Started

  • composer require ghanem/multiple-date-picker, then confirm the package auto-registers (Nova packages usually ship a NovaServiceProvider-style provider via composer.json extra.laravel.providers, or expose a publish tag). If a dist/ folder isn't committed, run npm install && npm run prod inside vendor/ghanem/multiple-date-picker — Nova fields can't be compiled from your app's Vite config.
  • Read src/ first, then dist/js/field.js. With 0 stars and 0 dependents there is no blog post, no Stack Overflow trail, and no one to ask. The source is your documentation; the two things you need to confirm before writing a single migration are (a) the storage format the Vue component emits and (b) the laravel/nova constraint in composer.json — Nova 4 vs Nova 5 incompatibility is the most likely reason this package silently renders nothing.
  • Migration: almost certainly a JSON column.
    $table->json('blackout_dates')->nullable();
    
  • Model: cast it, or Nova will hand you a raw string and the field will throw on hydration.
    protected $casts = ['blackout_dates' => 'array'];
    
  • First use case: a BlackoutDate or Availability resource where an admin picks a handful of dates in one click instead of spawning repeaters or a third-party calendar UI. Best fit is a short, bounded list of discrete dates — this is not a date-range picker and it is not a scheduler.

Register it in a Nova resource:

use Ghanem\MultipleDatePicker\MultipleDatePicker;

MultipleDatePicker::make('Blackout Dates', 'blackout_dates')
    ->nullable()
    ->rules(['array']),

Implementation Patterns

Field definition on a JSON column. Keep the display compact and push formatting to a displayUsing callback so index views don't explode into a wall of ISO timestamps:

MultipleDatePicker::make('Blackout Dates')
    ->displayUsing(fn ($value) => collect($value ?? [])
        ->map(fn ($d) => \Carbon\Carbon::parse($d)->format('d M Y'))
        ->implode(', '))
    ->hideFromIndex(),

hideFromIndex() is often the right call — a multi-date field renders unpredictably in Nova's table cells, and detail views are where the picker earns its keep.

Validation. Nova applies rules to the field's single value, so nested rules go in as an array of strings with wildcards. This is the pattern that actually works:

->rules(['array'])
->rules(['*' => 'date'])

Do not write 'blackout_dates.*' => 'date' — Nova scopes the rule for you and the prefixed form silently fails to attach to anything.

Storage-format flexibility via fillUsing/resolveUsing. If you inherit a table that stores comma-separated dates (legacy), or you want to normalise to Y-m-d before saving while keeping the picker in ISO-8601, override at the field level rather than forking the package:

MultipleDatePicker::make('Blackout Dates')
    ->resolveUsing(fn ($value) => $value ? explode(',', $value) : [])
    ->fillUsing(function ($request, $model, $attribute) {
        $model->{$attribute} = collect($request->input($attribute, []))
            ->map(fn ($d) => \Carbon\Carbon::parse($d)->toDateString())
            ->unique()->sort()->values()->all();
    });

This is the main extension point and it's the reason the package is usable at all — the field class is thin, so overriding resolution and filling covers almost every mismatch between what the Vue component emits and what your column expects.

Filtering. Nova's built-in filter builders don't understand JSON arrays. Write a boolean/select filter that uses whereJsonContains:

public function apply(Request $request, $query, $value)
{
    return $query->whereJsonContains('blackout_dates', $value);
}

If you need "contains any of these dates", loop and orWhereJsonContains inside a nested where closure so the rest of the filter chain stays intact.

Pairing with a dependent field. ->dependsOn('some_field', ...) works as with any Nova field, but the picker needs a full re-render to pick up the new value — if the calendar doesn't refresh, force it with :key in a small custom field wrapper rather than patching the vendor component.

Form-only vs. detail. A practical split is ->onlyOnForms() for the picker plus a Text field with a displayUsing summary on index/detail. It avoids having to reason about how the component behaves in read-only mode, which is the least-tested path in most low-adoption Nova fields.

Gotchas and Tips

  • Verify the emitted value shape on day one. Newer Nova/Vue versions may hand back full ISO strings (2025-03-04T00:00:00.000Z) rather than Y-m-d. If you're storing into a DATE column or doing string comparisons, UTC offset drift will move dates by a day for users west of Greenwich. Normalise in fillUsing and don't trust the component.
  • ->sortable() will fail on MySQL JSON. ORDER BY meta->... on a JSON column errors unless you have a generated column and index. Either drop sortable() or add a stored generated column and sort on that.
  • ->searchable() is similarly a trap — Nova's default search does a LIKE on the column. It "works" on MySQL JSON in the sense that it doesn't throw, but results are unreliable. Filter instead.
  • Asset publishing is the usual first bug. If the field renders as a blank cell or a raw <input>, the JS bundle isn't loaded. Check php artisan nova:publish ran, check public/vendor/ghanem exists, and check the browser console for a failed app.js — this failure mode looks identical to a broken field.
  • Pin the version. Zero dependents means zero downstream validation; composer update can break you and nobody will file the issue. Use "ghanem/multiple-date-picker": "1.0.*" (adjust to the actual tag for the 2025-01-26 release) and only bump deliberately.
  • Set a ->default([]) alongside ->nullable() if the column is NOT NULL — the component can submit null when the user clears all selections, and a null written to an array cast comes back as null, not [], so every count() downstream needs a guard.
  • ->rules(['array']) alone permits an empty array — that's usually what you want, but if at least one date is required use ->rules(['array', 'min:1']) and add a custom message, otherwise the error text is Nova's generic "The field is invalid."
  • No tests ship with this package. Before adopting, write a single feature test that posts to your Nova resource update endpoint and asserts the column round-trips through the field — that one test is your regression net for the entire dependency.
  • Fork-friendly by design. Because the field is a thin Field subclass, the cleanest escape hatch if the release goes stale is to copy src/ into app/Nova/Fields/ and point the component at your own published asset directory. At 0 stars, assume you may end up owning this code and budget for it in the estimate.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect