digital-creative/batch-edit-toolbar
A Laravel Filament package that adds a batch edit toolbar to tables, letting users select multiple records and update shared fields in bulk. Streamline admin workflows with inline bulk editing directly from the resource list.
The package is a Laravel Nova add-on, not a general Laravel package. If you are not running Nova, stop here — there is nothing to leverage. Confirm your Nova version first; the last release (Oct 2023) predates Nova 5, so verify compatibility before committing.
composer require digital-creative/batch-edit-toolbar
No publish step is typically needed — the provider is auto-discovered and the package is intentionally thin. Look first at: the README snippet (the API surface is one class and a handful of fluent methods), then src/BatchEditToolbar.php if the README is ambiguous. With 8 stars and 0 dependents, the source is the documentation — read it before debugging behaviour, and vendor/patch it if needed rather than waiting on an upstream fix.
First use case — publishing many records at once:
use DigitalCreative\BatchEditToolbar\BatchEditToolbar;
public function fields(NovaRequest $request): array
{
return [
BatchEditToolbar::make()
->addFields([
Select::make('Status')->options([
'draft' => 'Draft',
'published' => 'Published',
])->rules('required'),
])
->onlyOnIndex(),
ID::make()->sortable(),
Text::make('Title'),
Select::make('Status')->options([/* ... */]),
];
}
Select rows in the index (or "select all"), click the toolbar, fill in the single field you configured, submit. The package applies that value to every selected resource. Keep the toolbar to one column per toolbar — that is the design intent per the description, and it keeps validation and the authorization story simple.
One toolbar per concern. Rather than one giant toolbar, add focused toolbars: a "Publish" toolbar for status, an "Assign owner" toolbar for user_id. Each is cheap and the UX is much clearer than a modal with five unrelated fields.
Share via a trait or base resource. In a multi-resource app, define the toolbar factory once:
trait HasBatchStatusToolbar
{
protected function batchStatusToolbar(): BatchEditToolbar
{
return BatchEditToolbar::make()
->addFields([
Select::make('Status')->options(static::statusOptions())->rules('required'),
])
->onlyOnIndex()
->canSee(fn (NovaRequest $request) => $request->user()->can('publish', static::newModel()));
}
}
Gate it with policies. The package runs through Nova's request lifecycle, so the resource's update ability and any canSee/canRun guards apply. Add an explicit ->canSee(...) for privileged columns (pricing, ownership) — do not rely on the field merely not being displayed.
Pair with Nova search/filter for targeting. The realistic workflow is: filter to "draft + category X", select all, publish. Because the toolbar honours whatever index query is active, users batch-edit sets, not tables. Document that in your UI.
Let model events do the heavy lifting. Each selected model is saved individually, so updated observers, activity logs, and audit trails fire normally. Put side effects (Slack notification, search reindex, cache bust) in the observer rather than in the toolbar config — that keeps batch edits and single edits behaving identically.
Combine with conditional containers (digital-creative/nova-conditional-container) inside the toolbar's field list if a field only makes sense for some states, e.g. a "publish at" DateTime that appears when status === published.
composer.json, and smoke-test batch edit against your Nova version after every Nova minor upgrade. If it breaks, expect to fix it yourself.onlyOnIndex() is mandatory. Nova fields are shared across index/detail/create/update. Without it, the toolbar (and its modal fields) will surface on forms where it makes no sense.Select::make('Status') inside the toolbar does not render a Status column. Declare the display field separately in fields().Text, Number, Select, Boolean, Date, Textarea, BelongsTo (test it).BelongsTo saving depends on Nova's saveRelationships behaviour; if the toolbar calls fill()/save() directly, foreign keys may not be set the way they are in the resource form. Verify with a BelongsTo before shipping, and fall back to a raw Select::make('user_id') keyed by ID if it misbehaves.handle(ActionFields, Models) with a transaction.->rules('required') works because Nova evaluates the field rules server-side; a failed rule surfaces as a modal error and blocks the update. Use ->rules() rather than controller-level validation you can't hook into.laravel/telescope will show the per-model updates.How can I help you explore Laravel packages today?