wehaa/inline-boolean-field-update
A Laravel Nova package that lets you toggle boolean fields directly from the index list without opening a detail view. Enable inline editing for true/false columns, reducing clicks for quick status updates.
Settle the version gate before running composer require. This field was built in the Nova 3 era (Vue 2 + Laravel Mix), with compiled assets frozen on 2021-05-31. Run composer show laravel/nova first. If you're on Nova 4.x or 5.x (Vue 3 + Vite), the shipped dist/js/field.js will not boot — the laravel-nova build alias it depends on doesn't exist in the new toolchain. Confirm the constraint in the package's own composer.json and smoke-test in a staging panel, never production.
Read the source before installing. The entire package is a few hundred lines. Clone it and inspect four things in order:
git clone https://github.com/wehaa/inline-boolean-field-update /tmp/ibfu
cd /tmp/ibfu
cat composer.json # Nova constraint + PSR-4 namespace
ls src/ # the Field class — small, note the exact class name
ls resources/js/ # the Vue component — where the write actually happens
ls dist/js/ # the compiled asset that runs at runtime
The single most important file is the Vue component. Grep it for the request it fires:
grep -nE "Nova.request|axios|nova-api|/update|method:" resources/js/**/*.vue
/nova-api/{resource}/{id} with PUT → you're going through Nova's update controller, so update policies, canSee, readonly, and form validation all still apply.Install as a pin, not a dependency. With 3 stars, 0 dependents, and no release since May 2021, treat upstream as abandoned from day one:
composer require wehaa/inline-boolean-field-update
# then pin the exact version/commit, or better, vendor it:
# "repositories": [{ "type": "path", "url": "packages/inline-boolean-field-update" }]
First use case: a low-consequence flag on the index. Pick something like is_featured — not is_published, not anything that gates access or billing:
use Wehaa\InlineBooleanFieldUpdate\InlineBooleanFieldUpdate; // verify namespace from src/
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('Name'),
InlineBooleanFieldUpdate::make('Active', 'is_active')->sortable(),
// keep the native field for the detail form so validation,
// updated_by, and reason fields survive on edit
Boolean::make('Active', 'is_active')->onlyOnDetail(),
];
}
First thing you test is the network call, not the UI. Open the resource index, DevTools → Network, click the toggle, and answer four questions: (1) What URL and method? (2) What status on success and on failure? (3) Does the UI revert if you block the request or force a 500? (4) assertDatabaseHas after a successful click — verify the DB, not the checkbox. A toggle that renders but doesn't persist is the expected failure mode here.
Keep the native Boolean on the detail form. The dominant production shape is inline toggle on the index for fast operator work, plus Nova's stock Boolean on the detail view where validation, updated_by, and reason-for-change fields live. Use ->onlyOnIndex() and ->onlyOnDetail() so the two fields don't collide on the same attribute.
Wire audit logging through model events, not the form. Model events still fire on inline writes, so observers and spatie/laravel-activitylog work unchanged:
public function updated(Model $model): void
{
if ($model->wasChanged('is_active')) {
activity()
->performedOn($model)
->causedBy(auth()->user())
->withProperties([
'from' => $model->getOriginal('is_active'),
'to' => $model->is_active,
])
->log('is_active toggled');
}
}
This is also how you recover the updated_by context an inline write otherwise strips. Do it before operators start using the toggle — retrofitting audit after the fact leaves a gap you can't backfill.
Gate visibility with Nova policies, but don't trust canSee alone. Hiding the button isn't authorizing the write:
InlineBooleanFieldUpdate::make('Active', 'is_active')
->canSee(fn (Request $request) => $request->user()->can('update', $this->resource))
Then write a feature test that logs in as a read-only user and asserts the toggle request returns 403 (or 404) and the DB value is unchanged.
Sorting and filters work because the field maps to a real column.
InlineBooleanFieldUpdate::make('Active', 'is_active')->sortable()
Your existing BooleanFilter still applies unchanged. Don't assume the toggle participates in filter state beyond what Nova does natively.
Customize colors/labels only if the package exposes setters. The description advertises on/off colors and labels, but the exact API is ->onColor() / ->offColor() / ->onText() / ->offText() style in most Nova field packages — confirm against the src/ Field class before writing resource code. If they don't exist, they're a five-line addition when you fork.
Restrict the blast radius deliberately. Adopt on one resource, one flag, for a week. Instrument usage — the activity log above gives you the count for free. If operators don't actually use the index toggle, you've spent half a day and learned the loop isn't worth optimizing.
Test the endpoint, not the component. A feature test around the update path covers the thing that matters and survives a JS rebuild:
public function test_index_toggle_persists_and_fires_events(): void
{
$record = Model::factory()->create(['is_active' => false]);
$this->actingAs($admin)
->putJson("/nova-api/models/{$record->id}", ['is_active' => true])
->assertOk();
$this->assertTrue($record->fresh()->is_active);
}
Bulk operations stay separate. Nova's bulk actions and this field are unrelated code paths. If operators need to flip ten records, that's a Nova Action — don't let the toggle's presence substitute for the bulk affordance.
Nova 4/5 will break this, and you can't fully audit the fix from the public repo. Rebuilding the assets requires the laravel-nova build alias, which only exists inside a licensed local Nova install. "Just run npm run prod" isn't something you can validate in CI without Nova available. Budget a rebuild plus smoke test into every Nova major upgrade as an explicit runbook step — that's precisely where the original package stopped being maintained.
The worst failure is silent. A compiled Vue asset against a mismatched Nova runtime can render a switch that looks correct and does nothing — or flips optimistically with no rollback. Verify the network response and the database, never the checkbox. If you fork, add explicit failure handling in the component: on non-2xx, revert the visual state and surface an error.
Model events fire; business-process context does not. updated/saved observers run, but anything your form relies on — updated_by auto-fill, a reason field, a workflow that reads request input — is absent. Any observer that assumes $request->input('reason') is present will null-reference on an inline toggle.
Fields that gate things need different treatment. If the boolean controls publication, access, billing, or tenant state, don't put an inline toggle on it. It strips the approval/reason context a regulated flow needs, and it's exactly the field where a mis-click is expensive. Reserve inline toggles for display flags, soft "active" markers, and internal feature flags.
CSRF / 419 on long-lived admin tabs. Inline writes are more sensitive to expired sessions than a full form save, because the operator is clicking rapidly and won't re-read the page. Verify the field handles a 419 gracefully (reload prompt) rather than leaving the UI desynced.
Validation is not automatic. Nova's detail-form rules don't meaningfully re-run for a single boolean, so any model-level guard — a DB constraint, a saving observer enforcing state transitions — becomes the only line of defense. If a boolean is only valid to flip from certain states, enforce it in the observer; the inline UI won't.
Accessibility and keyboard support are almost certainly missing. A 2021 custom toggle is usually a styled <div> with a click handler, not a real <input type="checkbox"> with focus states. If operators use keyboards or you have accessibility requirements, that's a reason to build natively from Nova's official scaffolding — likely under a day at this surface area — rather than retrofit.
Extension points are narrow, so fork instead of patching around it. There's no meaningful service provider, config, or migration surface. If you need different styling, an audit hook, or rollback behavior, you're editing the Field class and the Vue component directly — which is fine, because that's the whole package. Vendor it into packages/ or a private repo under your namespace, pin it, and treat the public repo as a reference implementation. That also removes the pre-compiled dist/ trust question: you build the asset yourself from source you've read.
Debugging checklist when the toggle no-ops:
laravel-nova or Vue → version mismatch.fillable/cast issue.saving observer error → observer assumes form-only input.How can I help you explore Laravel packages today?