Bulk actions let users select rows and perform operations on them. The system uses an exclusion model for efficient handling of large datasets.
Enabling Bulk Actions
Define the bulkActions() method in your table component to enable bulk actions:
public function bulkActions(): array
{
return [
'deleteSelected' => 'Delete Selected',
'exportSelected' => 'Export to CSV',
'activateSelected' => 'Activate',
];
}
Each key is the method name to call, and the value is the display label shown in the dropdown.
When bulkActions() returns actions, a checkbox column is automatically added to the table.
Implementing Action Methods
Define a public method for each action. Use getSelectedIds() to retrieve the selected row IDs:
public function deleteSelected(): void
{
$ids = $this->getSelectedIds();
User::whereIn('id', $ids)->delete();
}
public function activateSelected(): void
{
$ids = $this->getSelectedIds();
User::whereIn('id', $ids)->update(['active' => true]);
}
After execution, deselectAll() is called automatically to clear the selection.
The Exclusion Model
The package uses an intelligent selection model that efficiently handles millions of rows:
Individual Selection (default)
Clicking individual checkboxes stores IDs in the $selectedIds array.
Select All Pages
When “Select All” is clicked across all pages:
selectAllPages is set to true
- All rows are considered selected
- Unchecked rows are tracked in
$excludedIds
This means “all rows EXCEPT the excluded ones” — efficient even with millions of rows. Getting Selected IDs
getSelectedIds() intelligently resolves IDs based on the current mode:
- In individual mode: returns
$selectedIds array
- In exclusion mode: queries the database for all matching IDs minus
$excludedIds
Active search and filters are respected when resolving IDs in exclusion mode.
How getSelectedIds() Works
Here’s the implementation from DataTableComponent.php:78:
public function getSelectedIds(): array
{
if (! $this->selectAllPages) {
return $this->selectedIds;
}
$columns = $this->resolveColumns();
$filters = $this->filters();
$state = new State(search: $this->search, filters: $this->tableFilters);
$query = $this->query();
$query = (new SearchStep($columns))->apply($query, $state);
$query = (new FilterStep($filters))->apply($query, $state);
$keyName = $query->getModel()->getKeyName();
$allIds = $query->pluck($keyName)->map(fn ($id) => (string) $id)->toArray();
return array_values(array_diff($allIds, $this->excludedIds));
}
The method uses the model’s actual primary key (getKeyName()), so custom primary keys and UUIDs work correctly.
Built-in CSV Export
The HasExport trait provides automatic CSV export from visible columns without manual mapping:
public function bulkActions(): array
{
return [
'exportCsvAuto' => 'Export CSV',
];
}
That’s it! exportCsvAuto() automatically:
- Uses visible column labels as CSV headers
- Resolves cell values via each column’s
resolveValue() method
- Excludes
blade, action, and image column types
- Respects active search, filters, and sort
- When bulk selection is active, exports only selected rows
- Streams the download (memory-efficient for large datasets)
Configuration
Customize the export filename and chunk size in your configure() method:
public function configure(): void
{
$this->setExportFilename('users'); // Default: 'export'
$this->setExportChunkSize(1000); // Default: 500
}
The filename is suffixed with the current date: users-2024-12-15.csv
Custom Export Logic
For full control over export format and content, build your own export method:
use SymfonyComponentHttpFoundationStreamedResponse;
public function exportCsv(): StreamedResponse
{
$ids = $this->getSelectedIds();
return response()->streamDownload(function () use ($ids): void {
$out = fopen('php://output', 'w');
fputcsv($out, ['ID', 'SKU', 'Name', 'Category', 'Brand', 'Price', 'Stock', 'Rating', 'Country', 'Active']);
CatalogItem::whereIn('id', $ids)
->orderBy('id')
->chunk(500, function ($items) use ($out): void {
foreach ($items as $item) {
fputcsv($out, [
$item->id,
$item->sku,
$item->name,
$item->category,
$item->brand,
number_format((float) $item->price, 2),
$item->stock,
$item->rating,
$item->country,
$item->active ? 'Yes' : 'No',
]);
}
});
fclose($out);
}, 'catalog-export-'.now()->format('Y-m-d').'.csv', [
'Content-Type' => 'text/csv',
]);
}
Available Methods
bulkActions()
Define available bulk actions as an associative array
getSelectedIds()
Get resolved IDs (handles exclusion model automatically)
toggleSelected($id)
Toggle selection state of a single row
setPageSelection($ids, $select)
Select or deselect all rows on current page
selectAllAcrossPages()
Enter exclusion mode (select everything)
deselectAll()
Clear all selections and exit exclusion mode
getSelectedCount($total)
Get count of selected rows
hasBulkActions()
Check if any bulk actions are defined
executeBulkAction($action)
Execute a bulk action by name (called internally)
UI Behavior
Initial State
The bulk actions dropdown is disabled when no rows are selected.
Selection Active
A badge shows the count of selected rows, and the dropdown becomes active.
Page Fully Selected
A “Select all across pages” banner appears when all visible rows are selected.
Exclusion Mode
The banner shows the total selected count. Unchecking rows adds them to the exclusion list.
Active search and filters are respected when resolving IDs in exclusion mode, ensuring bulk actions only affect the filtered dataset.