Skip to content
Zonvoir Table LogoZonvoir Table

Bulk Actions & Multi-Row Operations

Bulk actions let users select multiple rows and perform an action against all selected records at once.

Bulk actions use the same Action class as row actions, so options such as icons, variants, colors, and confirmation can be shared between them.

Use asBulkAction() to make an action available for selected rows.

use Zonvoir\ZonvoirTable\Action;
Action::make('Archive selected')
->asBulkAction()
->handle(
fn ($records) => $records->each->archive()
);

When rows are selected, the action becomes available from the table’s bulk action area.

The handler receives the selected records.

asBulkAction() makes an existing action available as a bulk action while still allowing it to be used as a row action.

Action::make('Archive')
->icon('mdi:archive')
->asBulkAction()
->handle(
fn ($records) => $records->each->archive()
);

Use this when the same operation should be available for both an individual record and multiple selected records.

Use onlyAsBulkAction() when an action should appear only when rows are selected.

Action::make('Delete selected')
->onlyAsBulkAction()
->asDangerButton()
->confirm('Delete selected records?')
->handle(
fn ($records) => $records->each->delete()
);

The action will not appear as an individual row action.

This is useful for operations that only make sense when working with a selection.

Method Row action Bulk action
asBulkAction()
onlyAsBulkAction()

For example, an archive operation might be useful both individually and in bulk:

Action::make('Archive')
->asBulkAction()
->handle(
fn ($records) => $records->each->archive()
);

While an operation specifically designed around a selection can remain bulk-only:

Action::make('Delete selected')
->onlyAsBulkAction()
->handle(
fn ($records) => $records->each->delete()
);

Bulk operations can affect many records at once, so destructive actions should usually require confirmation.

Action::make('Delete selected')
->onlyAsBulkAction()
->asDangerButton()
->confirm(
'Delete selected records?',
'This action cannot be undone.'
)
->handle(
fn ($records) => $records->each->delete()
);

The frontend adapter displays the confirmation before the action is submitted.

Bulk actions can process selected records in chunks.

Specify the strategy when configuring the bulk action:

Action::make('Delete selected')
->onlyAsBulkAction(strategy: 'chunk')
->handle(
fn ($records) => $records->each->delete()
);

Supported strategies are:

Strategy Description
chunkById Processes records in chunks using their IDs.
chunk Processes records using standard chunking.

The default strategy is chunkById.

If an unsupported strategy is provided, Zonvoir Table falls back to chunkById.

For most bulk actions, chunkById is the recommended strategy.

Action::make('Archive selected')
->onlyAsBulkAction(strategy: 'chunkById')
->handle(
fn ($records) => $records->each->archive()
);

Processing records in chunks avoids loading a large selection into memory at once.

Use the chunk strategy when standard query chunking is more appropriate for your operation.

Action::make('Archive selected')
->onlyAsBulkAction(strategy: 'chunk')
->handle(
fn ($records) => $records->each->archive()
);

Bulk actions are returned from the same actions() method as row actions.

public function actions(): array
{
return [
Action::make('Edit')
->icon('mdi:pencil')
->url(
fn (User $user, Url $url) =>
$url->route('users.edit', $user)
),
Action::make('Archive')
->icon('mdi:archive')
->asBulkAction()
->confirm(
'Archive selected records?',
'You can restore them later.'
)
->handle(
fn ($records) => $records->each->archive()
),
Action::make('Delete selected')
->icon('lucide:trash-2')
->onlyAsBulkAction(strategy: 'chunkById')
->asDangerButton()
->confirm(
'Delete selected records?',
'This action cannot be undone.'
)
->handle(
fn ($records) => $records->each->delete()
),
];
}

In this example:

  • Edit is available for individual rows.
  • Archive is available as both a row and bulk action.
  • Delete selected appears only as a bulk action.