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

Nova Improved Date Field Laravel Package

gabelbart/nova-improved-date-field

An improved date field for Laravel Nova that gives you more control over how dates and times are displayed and edited in your admin panel, with flexible formatting options and a cleaner, more intuitive picker experience for your resources.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require gabelbart/nova-improved-date-field

No manual provider registration is normally required — Nova fields are plain PHP classes resolved at resource-definition time. If the package ships a service provider for publishing JS assets, run:

php artisan vendor:publish --provider="Gabelbart\NovaImprovedDateField\FieldServiceProvider"
php artisan nova:publish

Where to look first

  1. vendor/gabelbart/nova-improved-date-field/src/ — the field class itself. This is where the real API lives; the README on GitLab is thin, but the class exposes everything the Vue component accepts.
  2. vendor/gabelbart/nova-improved-date-field/resources/js/ — the picker component and its flatpickr options. Any option you can't find a PHP setter for is usually still reachable by inspecting how the component consumes field.* props.
  3. The GitLab repo (jacobfricke/nova-configurable-date-field) — note the package is a repackaged fork, so the upstream README/source is your fallback documentation.

First use case

The canonical use is a published_at / starts_at datetime column where you want a display format, an input format, and consistent timezone behaviour across form, index, and detail views:

use Gabelbart\NovaImprovedDateField\ImprovedDate;

ImprovedDate::make('Published At', 'published_at')
    ->format('DD/MM/YYYY HH:mm')   // what the user sees in index/detail
    ->pickerFormat('d/m/Y H:i')    // what flatpickr shows in the form
    ->rules('nullable', 'date')
    ->sortable(),

Pair it with a model cast ('published_at' => 'datetime') and you have a working field in under five minutes.


Implementation Patterns

Centralise the field definition

Because you'll use the same format everywhere, don't repeat format()/pickerFormat() across resources. Put a factory on a base resource or a trait:

trait HasDateFields
{
    protected function dateTime(string $name, ?string $attribute = null): ImprovedDate
    {
        return ImprovedDate::make($name, $attribute ?? Str::snake($name))
            ->format('DD/MM/YYYY HH:mm')
            ->pickerFormat('d/m/Y H:i')
            ->rules('nullable', 'date')
            ->sortable();
    }
}

Then $this->dateTime('Published At', 'published_at') in every resource. When the client asks for a format change, it's one edit.

Separate display format from input format

The single most important habit with this field: format() is a display concern (index, detail, and often the resolved value), while pickerFormat() is a flatpickr token string. They use different token languages:

Token format() (PHP-ish / display) pickerFormat() (flatpickr)
Day d d
Month m m
Year Y Y
Hour (24h) H H
Minutes i i
Seconds s S

Note i vs S for seconds and the fact that flatpickr's i is minutes — this trips people up constantly. If your index shows the wrong time, you mixed the two up.

Date-only columns

For date (not datetime) columns, use the field but force a date-only picker — otherwise users can attach a time that MySQL will silently truncate:

ImprovedDate::make('Due Date', 'due_date')
    ->format('DD/MM/YYYY')
    ->pickerFormat('d/m/Y')
    ->rules('nullable', 'date_format:Y/m/d'),

Verify the date_format rule matches what Nova actually submits post-picker, not what the user typed.

Timezone handling

Nova's base DateTime ships ->timezone()-style helpers for displaying in a user's tz while storing UTC. Before relying on it, check the vendored class — forks of this nature often patch or drop that behaviour. The safe pattern is to keep the model casting timezones and let the field be a pure presentation layer:

// app/Models/Event.php
protected $casts = ['starts_at' => 'datetime'];

If the field does expose a timezone setter, apply it consistently in forms and index, otherwise the same row shows two different times to the same user.

Forms with validation and updateUsing

When you need to transform the incoming value (e.g. combine a date with a default time):

ImprovedDate::make('Starts At')
    ->rules('required', 'date')
    ->updateUsing(fn ($value) => Carbon::parse($value)->startOfHour())
    ->resolveUsing(fn ($value) => $value?->format('d/m/Y H:i'));

resolveUsing lets you keep the field's display contract stable even if the underlying column format changes.

Index vs form differentiation

Nova lets you trim per-view:

ImprovedDate::make('Archived At')
    ->hideFromIndex()          // keep index uncluttered
    ->sortable()
    ->exceptOnForms();         // detail only

Combined with ->onlyOnDetail() / ->onlyOnForms(), one field class covers every view without duplicate definitions.

Filters and metrics

If you write a Nova filter comparing dates, instantiate the same field class or at least reuse the pickerFormat constant — otherwise the filter UI's date picker produces 2024-01-31 while your field produces 31/01/2024, and nothing matches.

public function apply(Request $request, $query, $value)
{
    return $query->whereDate('starts_at', Carbon::parse($value));
}

Always Carbon::parse() user input in the filter; never compare raw strings.


Gotchas and Tips

Fork provenance and maintenance risk

The repo is gitlab.com/jacobfricke/nova-configurable-date-field but the package is published as gabelbart/nova-improved-date-field with zero dependents. Treat it as effectively unmaintained: pin an exact version in composer.json, and be prepared to vendor the class into app/Nova/Fields/ if a Nova major bumps the Vue component contract. Before upgrading Nova, diff the field class against Nova's own DateTime — most breakage is a renamed field.* prop.

Blank or unstyled picker after install

Almost always unpublished assets or a stale build. Fix in order:

php artisan nova:publish
php artisan view:clear && php artisan config:clear
npm run dev   # if the package ships source

Check the browser console for a Vue "unknown component" warning — that means the JS never loaded, not that your PHP is wrong.

null saved when the user picks a valid date

Format mismatch between the picker and the server. The submitted string is parsed by Laravel's date rule / Carbon, and 31/01/2024 is ambiguous or invalid depending on locale. Log the raw $request->all() on the failing submit — if the value is there but the model attribute is null, it's a cast/format problem, not a picker problem.

format() silently ignored on index

Some Nova versions render DateTime fields via the resolved value's own __toString, bypassing the field's format. If the index ignores your format, force it:

->displayUsing(fn ($value) => $value?->format('d/m/Y H:i'))

DateTime vs date column

If the column is DATE, passing a full datetime string to MySQL 5.7+ strict mode throws. Either switch the column to DATETIME or ensure pickerFormat really has no H/i tokens. Don't rely on the field to guess.

Sorting on a formatted field

->sortable() sorts by the underlying column, not the displayed string — which is correct, but users will report "wrong order" when the display format is DD/MM/YYYY (looks like day-first but sorts by ISO). Either sort on the real column and accept it, or provide a tooltip/label clarifying the format.

Validation runs against the picker string

'date' accepts most formats, but 'date_format:d/m/Y H:i' is exact and unforgiving — a trailing space or a stray seconds segment fails. Debug by dumping the raw input in a FormRequest before the rule fires. For flexible input, use 'date' plus a mutator that normalises:

public function setStartsAtAttribute($value) {
    $this->attributes['starts_at'] = $value ? Carbon::parse($value) : null;
}

Extension points worth knowing

  • ->resolveUsing() / ->fillUsing() / ->displayUsing() — escape hatches when a fork method is missing; you rarely need to patch the package.
  • The Vue component's flatpickr options — expose extra picker behaviour (week numbers, minDate, locale) via ->withMeta([...]) and read it in the component, or by extending the field class with a small setter.
  • ->default() — pair with now() carefully; a default of Carbon::now() on a date field will include a time the column can't hold.

Test the three surfaces every time

Add one row, then check index, detail, and the edit form. The field resolves values through different paths in each (index may use displayUsing, detail may use format, the form uses pickerFormat). Most "it works but..." reports are one of these three diverging, and this field's fork status means upstream won't catch it for you.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle