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 Defaultable Laravel Package

inspheric/nova-defaultable

Nova Defaultable lets Laravel Nova fields and resource forms start with sensible prefilled values, reducing repetitive data entry. Configure defaults once and streamline create workflows across your Nova admin panels.

View on GitHub
Deep Wiki
Context7

Getting Started

What you're buying: a thin Nova add-on that attaches a default() value to individual field definitions and applies it when a form renders for a new model — and, since v1.2, inside resource action modal fields too, plus a defaultLast() fallback variant. It is a trait + a service provider; that's the whole package.

Install and pin the version that matters:

composer require inspheric/nova-defaultable-fields:^1.2
ls vendor/inspheric/nova-defaultable-fields/src

Pin ^1.2. An older constraint silently skips action support, and you'll spend an afternoon debugging the wrong layer.

Read the source before you read the README. It's short enough to finish in one sitting, and it's the authoritative answer to "does my installed version expose default, defaultLast, or both, and in what precedence order." With a package last released in 2019 and 51 stars, the vendor source and your composer.lock are the only documentation you can trust.

First use case — a "draft by default" create form:

use Laravel\Nova\Fields\Text;
use Laravel\Nova\Fields\Select;
use Laravel\Nova\Fields\DateTime;

public function fields(Request $request)
{
    return [
        Text::make('Title')
            ->default(fn () => 'Untitled'),

        Select::make('Status')
            ->options(['draft' => 'Draft', 'published' => 'Published'])
            ->default('draft'),

        DateTime::make('Publish At')
            ->default(fn () => now()->addDay()),
    ];
}

Then verify the whole contract in three clicks:

  1. /nova/resources/posts/new → fields prefilled.
  2. Save → those values persist.
  3. /nova/resources/posts/1/edit → you see stored values, not defaults.

If step 3 shows defaults, stop. That's the entire promise of the package failing, and everything downstream is unreliable.

Second check — an action modal (the v1.2 feature):

public function fields(NovaRequest $request)
{
    return [
        Select::make('Status')
            ->options(['draft' => 'Draft', 'published' => 'Published'])
            ->default('published'),
    ];
}

Open the action. Prefilled means action support is firing. Blank means it isn't — fall back to vendoring the trait rather than fighting Nova version drift.

Implementation Patterns

Static defaults for enums, flags, and codes. Select, Boolean, Text with a literal ('draft', true, 'GB'). Highest value per line of code; zero timing or type risk.

Closure defaults for context-aware values. Defaults resolve at render time, so closures can read the request, the authenticated user, or the current tenant:

Text::make('Reference')
    ->default(fn () => 'INV-' . now()->format('Ym') . '-')
    ->hideWhenCreating()
    ->readonly(fn () => false);

BelongsTo::make('Owner', 'owner', User::class)
    ->default(fn ($request) => $request->user()->id)
    ->hideWhenCreating(),

Keep these pure and cheap — they run on every form render. No queries, no service calls, no N+1.

hideWhenCreating() pairs naturally with defaults. When the value is implied ("owned by me", "created in this month"), default it and hide the input. The default still rides along in the request as long as the field is visible — which is why hideWhenCreating() combined with a default is a hazard worth testing (see Gotchas).

Action defaults are the real v1.2 payoff. Confirmation-style actions — "Assign to…", "Duplicate as draft", "Move to status" — should open on a sensible value so the operator confirms with one click instead of filling a form. Write action fields with exactly the same idioms as resource fields; the two surfaces now share a mechanism, and legibility between them is the point:

class MoveToPublished extends Action
{
    public function fields(NovaRequest $request)
    {
        return [
            Select::make('Status')
                ->options(['draft' => 'Draft', 'published' => 'Published'])
                ->default('published'),
            DateTime::make('Publish At')
                ->default(fn () => now()),
        ];
    }
}

defaultLast() is a fallback, not a second default. default() wins when the field has no value; defaultLast() supplies one only when nothing else provided it. Use it for genuinely optional fields — e.g. a Notes field in an action modal that gets boilerplate only if no other default, meta, or resolved value exists. The release notes flag it as a caveat/workaround, so prove precedence with a test rather than trusting the name.

Keep one source of truth for business defaults. Encode them once and spread them into both surfaces:

private function defaults(): array
{
    return [
        'status'     => 'draft',
        'owner_id'   => optional(request()->user())->id,
        'publish_at' => now()->addDay(),
    ];
}

Silent divergence between the create form and the "Duplicate as draft" action is the failure mode this package enables — a shared accessor is the cheap insurance.

Type-correct values. DateTime wants a Carbon or a string parsed consistently with your other fields; Boolean wants a real bool; BelongsTo wants a foreign key, not a model. Wrong types don't error — they show as silent nulls in the UI.

Test the resolved payload in three scenarios. A fresh resource (default present), an existing resource (stored value, no default), and the action modal (default present, correct precedence). Assert on $field->jsonSerialize() or the field's meta value. Those three tests catch every "leaked into edit" and "modal opened blank" regression you'll ever hit.

Gotchas and Tips

  • Create-only semantics are the contract. Defaults must apply when the model is new and must not apply on edit. If yours apply everywhere, you've overridden value globally instead of honouring the create condition — and you'll be "fixing" data overwrites in production.
  • Action support is version-gated. default() inside an action's fields() is v1.2 behaviour. With ^1.0 pinned or a stale lockfile, the call does nothing and fails silently. Check composer.lock before debugging the field.
  • One default per field, enforced in review. default() and defaultLast() on the same field is a latent bug. Make "exactly one" a code-review rule, and if you use defaultLast() at all, write a test that asserts which value actually lands in the payload.
  • Hidden fields never persist. A default on a field removed by hideWhenCreating(), onlyOnIndex(), or canSee => false is display-only — it never reaches the request. Keep a real database default in the migration and/or protected $attributes for anything created outside Nova: seeders, imports, APIs, queue jobs.
  • Closures resolve outside a normal form request. Index/detail contexts, standalone and queued actions, and artisan commands may have no meaningful request or authenticated user. Guard with optional($request->user()) and fall back to a static value rather than letting a closure blow up in an action modal.
  • Last writer wins. ->default() competes with ->withMeta(['value' => ...]), ->resolveUsing(), and ->fillUsing(). Pick one convention per field; stacking them and hoping for a merge is how "the default doesn't work" tickets get written.
  • Composer constraint friction is likely. A 2019-era package often pins laravel/nova to older majors. Prefer a forked/path repository with a widened constraint over --ignore-platform-reqs in CI, which hides genuine incompatibility behind a green build.
  • Debug by dumping the payload, not the code. In a throwaway resource or a Nova test, dump $field->jsonSerialize() / $field->meta() to see whether the default reached the payload — that separates "package didn't fire" from "field was hidden or overwritten downstream." For action modals, dump inside the action's fields() to confirm you're even on that code path.
  • The extension point is replacement. It's a single MIT trait. The clean exit is copying it into app/Nova/Concerns/Defaultable.php with identical call sites, or dropping it entirely for ->withMeta(['value' => $this->status ?? 'draft']) plus model-level $attributes. If you depend on defaultLast(), verify your fork reproduces the precedence you rely on. Treat it as a convenience you own — not a dependency you rely on.
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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource