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

Laravel Flatpickr Laravel Package

asdh/laravel-flatpickr

Laravel Flatpickr integrates the lightweight Flatpickr date and time picker with Blade components and fluent configuration. Bind values to models, set formats, locales, themes, and options, and add responsive pickers to forms with minimal JavaScript boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require asdh/laravel-flatpickr

Publish what you need, then look at the config first

php artisan vendor:publish --tag=flatpickr-config   # config/flatpickr.php
php artisan vendor:publish --tag=flatpickr-assets   # public assets (if not using CDN)

config/flatpickr.php is the source of truth for this package — read it before writing any markup. It controls the default flatpickr option set (date format, locale, theme, whether assets are loaded from CDN or locally, and any asset stack the package pushes to). Because the package is a thin wrapper, the config file is where you'll spend most of your integration time.

Wire assets into your layout once

The package typically registers its scripts/styles against a Blade stack. Check the README for the exact stack name and add it to your base layout after your own JS bundle if you intend to override defaults:

{{-- resources/views/layouts/app.blade.php --}}
@stack('scripts')

First use case — a single date field on a form

The lowest-friction path is a plain input plus the package's init hook (component, directive, or data- attribute — check the README, the surface is small):

<input type="text" name="starts_on" id="starts_on" value="{{ old('starts_on') }}">

Then initialise it with the package's global helper so the config defaults apply:

// if the package exposes a JS init hook
window.flatpickr?.('#starts_on', { dateFormat: 'Y-m-d' });

Sanity check before building on it: render one input in a scratch route and confirm the picker opens and the value posts back in the format your migration expects (Y-m-d for a date column). If that round-trips, everything else is configuration.

Implementation Patterns

Pattern 1 — Config-driven defaults, per-field overrides

Set the project-wide display format once in config/flatpickr.php, then treat the picker as a dumb presenter. The single most common production bug here is display format leaking into persistence: flatpickr's dateFormat is what gets submitted, so if users see d/m/Y your controller receives d/m/Y. Use altInput + altFormat so the visible value is human-friendly while the hidden input stays ISO:

// config/flatpickr.php
'options' => [
    'dateFormat' => 'Y-m-d',   // what is submitted
    'altInput'   => true,
    'altFormat'  => 'd M Y',   // what the user sees
    'allowInput' => true,
],

Pattern 2 — One initialiser for a whole form

Rather than hand-wiring each field, mark inputs declaratively and let a single delegated initialiser sweep the page. This keeps markup self-documenting and survives partials being included in different orders:

<input type="text" name="starts_on" data-flatpickr data-flatpickr-options='{"minDate":"today"}'>
<input type="text" name="ends_on"   data-flatpickr data-flatpickr-options='{"minDate":"today"}'>
document.querySelectorAll('[data-flatpickr]').forEach((el) => {
    const opts = el.dataset.flatpickrOptions ? JSON.parse(el.dataset.flatpickrOptions) : {};
    window.flatpickr(el, opts);
});

Note the data-flatpickr-options payload is JSON inside an attribute — wrap it in single quotes in Blade or you'll fight HTML escaping.

Pattern 3 — Date ranges need onChange, not two independent pickers

For a start/end pair, link them so the second picker can't precede the first. This is the pattern that pays for the package in the first place:

const end = window.flatpickr('#ends_on');
const start = window.flatpickr('#starts_on', {
    onChange: ([date]) => { if (date) end.set('minDate', date); },
});

Pattern 4 — Pair every picker with a matching validation rule

The picker is a UI constraint, never a security boundary. Whatever dateFormat (or altInput submission format) you settled on, mirror it in the FormRequest:

'starts_on' => ['required', 'date_format:Y-m-d', 'after_or_equal:today'],
'ends_on'   => ['required', 'date_format:Y-m-d', 'after_or_equal:starts_on'],

Pattern 5 — Livewire / Alpine / Turbo integration

Any framework that swaps DOM nodes will orphan a flatpickr instance. Initialise in the lifecycle hook that fires after the swap, not on page load:

// Livewire 3
document.addEventListener('livewire:navigated', initPickers);

// Alpine, per-component
x-init="$nextTick(() => window.flatpickr($refs.date))"

// Turbo
document.addEventListener('turbo:load', initPickers);

Guard against double-init by checking el._flatpickr before calling again, or destroy on teardown.

Pattern 6 — Locale and timezone discipline

Locale is a config concern (locale + the flatpickr l10n bundle); timezone is not handled by flatpickr at all. It emits a naive local string. Decide once whether a date field is a calendar date (store as date, no timezone) or an instant (store as timestamp/datetime and convert explicitly server-side via the app timezone). Don't let Carbon parse() guess.

Gotchas and Tips

  • The format round-trip is the whole ballgame. dateFormat is the submitted value. If validation fails with "does not match format", compare config('flatpickr.options.dateFormat'), the altFormat, and your date_format: rule side by side — three places to keep in sync.
  • altInput changes the DOM. flatpickr hides your real input and injects a sibling. document.getElementById('starts_on') still works for reading the value, but jQuery selectors for styling/labels often break. Style via the generated .flatpickr-input class.
  • Publish assets vs CDN. If the config defaults to CDN, you have an external dependency in your render path and no offline/dev guarantee. Publish and Vite-bundle it for anything going to production, and pin the flatpickr version yourself — this package's last release is March 2024, so it will drift from upstream flatpickr.
  • Config cache. After editing config/flatpickr.php run php artisan config:clear. A stale cached config is the most common "my options are ignored" cause.
  • Double-init on partial reloads. Two instances on one element produce duplicate popups and confusing onChange behaviour. Always if (!el._flatpickr) before initialising, and el._flatpickr.destroy() before removing nodes.
  • minDate: 'today' is evaluated at init time. Long-lived tabs and Livewire components that persist for hours will hold a stale "today." Re-init or call set('minDate', ...) on focus if that matters.
  • Debugging: flatpickr attaches the instance to the element as _flatpickr. el._flatpickr.currentYear, .selectedDates, and .config tell you instantly whether your options actually reached the library or died in the Blade attribute/config layer.
  • Extension point: for options the package doesn't surface in config, pass them straight through as a per-input JSON blob (Pattern 2) rather than editing vendor files. Keep all package-specific glue in one small JS file so you can swap the wrapper out if it goes unmaintained.
  • Bus factor: 64 stars, zero dependents, thin wrapper. Budget for vendoring it — the whole value is ~50 lines of Blade/asset registration, so replacing it with a hand-rolled @push('scripts') block is a realistic escape hatch if a Laravel major version breaks it.
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