Filament v3 Bulk Actions: Jobs, Progress &amp; Confirmation | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com) [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles  ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Filament v3 Table Bulk Actions: Custom Confirmation, Progress Feedback, and Job Dispatch        On this page       1. [  The Problem With Default Bulk Actions ](#the-problem-with-default-bulk-actions)
2. [  1. Custom Confirmation Modal With Extra Fields ](#1-custom-confirmation-modal-with-extra-fields)
3. [  2. Dispatching a Laravel Job Batch ](#2-dispatching-a-laravel-job-batch)
4. [  3. Real-Time Progress Feedback ](#3-real-time-progress-feedback)
5. [  4. Safety Details Worth Getting Right ](#4-safety-details-worth-getting-right)
6. [  Takeaways ](#takeaways)

  ![Filament v3 Table Bulk Actions: Custom Confirmation, Progress Feedback, and Job Dispatch](https://cdn.msaied.com/412/68d290c667a619900211863678fa0b1f.png)

  #filament   #laravel   #queues   #livewire  

 Filament v3 Table Bulk Actions: Custom Confirmation, Progress Feedback, and Job Dispatch 
==========================================================================================

     11 Jul 2026      3 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   The Problem With Default Bulk Actions  ](#the-problem-with-default-bulk-actions)
2. [  02   1. Custom Confirmation Modal With Extra Fields  ](#1-custom-confirmation-modal-with-extra-fields)
3. [  03   2. Dispatching a Laravel Job Batch  ](#2-dispatching-a-laravel-job-batch)
4. [  04   3. Real-Time Progress Feedback  ](#3-real-time-progress-feedback)
5. [  05   4. Safety Details Worth Getting Right  ](#4-safety-details-worth-getting-right)
6. [  06   Takeaways  ](#takeaways)

 The Problem With Default Bulk Actions
-------------------------------------

Filament ships with `DeleteBulkAction` and a handful of helpers, but real applications need bulk actions that:

- Ask for extra input before running (e.g. a reason, a target status)
- Dispatch work to a queue instead of blocking the request
- Show the user meaningful feedback when the batch finishes

This article walks through all three concerns with production-ready code.

---

1. Custom Confirmation Modal With Extra Fields
----------------------------------------------

The `requiresConfirmation()` helper gives you a yes/no dialog. For richer input, swap to `form()` on the action:

```php
BulkAction::make('archive')
    ->label('Archive Selected')
    ->icon('heroicon-o-archive-box')
    ->form([
        Textarea::make('reason')
            ->label('Archive reason')
            ->required()
            ->maxLength(500),
    ])
    ->action(function (Collection $records, array $data): void {
        ArchiveRecordsJob::dispatch(
            $records->modelKeys(),
            $data['reason'],
            auth()->id(),
        );
    })
    ->deselectRecordsAfterCompletion()
    ->successNotificationTitle('Archive queued')
    ->color('warning');

```

The `form()` closure receives validated `$data` alongside `$records`. Filament renders the fields inside the confirmation modal automatically — no custom Livewire component needed.

---

2. Dispatching a Laravel Job Batch
----------------------------------

Passing raw model keys (not Eloquent models) to the job keeps the serialized payload small and avoids stale model state:

```php
// app/Jobs/ArchiveRecordsJob.php
final class ArchiveRecordsJob implements ShouldQueue
{
    use Queueable, Dispatchable, InteractsWithQueue, SerializesModels;

    public function __construct(
        private readonly array $ids,
        private readonly string $reason,
        private readonly int $actorId,
    ) {}

    public function handle(): void
    {
        Post::whereIn('id', $this->ids)
            ->lazyById(200)
            ->each(function (Post $post): void {
                $post->archive($this->reason, $this->actorId);
            });
    }
}

```

For very large selections, split into a **job batch** so each chunk runs independently and failures are isolated:

```php
->action(function (Collection $records, array $data): void {
    $chunks = array_chunk($records->modelKeys(), 100);

    $batch = Bus::batch(
        collect($chunks)->map(
            fn (array $ids) => new ArchiveRecordsJob($ids, $data['reason'], auth()->id())
        )->all()
    )
    ->name('archive-posts-' . now()->timestamp)
    ->allowFailures()
    ->dispatch();

    // Persist batch ID so the UI can poll it
    session()->put('archive_batch_id', $batch->id);
})

```

---

3. Real-Time Progress Feedback
------------------------------

Store the batch ID in the session (or a DB record keyed to the user) and expose a Livewire polling component in your Filament page footer via a render hook:

```php
// AppServiceProvider::boot()
Filament::registerRenderHook(
    PanelsRenderHook::BODY_END,
    fn (): View => view('filament.batch-progress'),
);

```

```xml
{{-- resources/views/filament/batch-progress.blade.php --}}
@if(session('archive_batch_id'))

    @livewire('batch-progress-indicator', [
        'batchId' => session('archive_batch_id')
    ])

@endif

```

The Livewire component calls `Bus::findBatch($this->batchId)` and exposes `$batch->progress()` (0–100) and `$batch->finished()`. When finished, dispatch a browser event to trigger a Filament notification and clear the session key.

---

4. Safety Details Worth Getting Right
-------------------------------------

**Authorization** — always gate the action:

```php
->authorize(fn (): bool => auth()->user()->can('archive', Post::class))

```

**Chunk size** — `lazyById` inside the job prevents loading thousands of models into memory at once. Tune the chunk size to your row width.

**`allowFailures()`** — without this, a single failing job cancels the entire batch. For archiving, partial success is usually acceptable; log failures via `->catch()` on the batch.

**Idempotency** — if a job retries, re-archiving an already-archived post should be a no-op. Guard with a status check at the top of `handle()`.

---

Takeaways
---------

- Use `form()` on `BulkAction` for confirmation modals that collect extra input before dispatch.
- Pass model keys (not models) to queued jobs to keep payloads lean.
- Split large selections into a `Bus::batch()` with `allowFailures()` for resilient processing.
- Persist the batch ID and poll `Bus::findBatch()` in a Livewire component for live progress.
- Always authorize bulk actions explicitly; Filament does not infer policy checks automatically.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Ffilament-v3-table-bulk-actions-custom-confirmation-progress-feedback-and-job-dispatch&text=Filament+v3+Table+Bulk+Actions%3A+Custom+Confirmation%2C+Progress+Feedback%2C+and+Job+Dispatch) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Ffilament-v3-table-bulk-actions-custom-confirmation-progress-feedback-and-job-dispatch) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  Can I access the form data inside the bulk action's `action()` closure?        Yes. When you define a `form()` on a BulkAction, Filament injects a validated `array $data` parameter alongside `Collection $records` in the `action()` closure. The keys match the field names you declared in the form. 

      Q02  How do I prevent the bulk action from timing out on very large selections?        Dispatch a queued job (or a Bus batch of jobs) from the action closure instead of processing records inline. The HTTP request returns immediately after dispatch, and the heavy work runs on your queue workers. Use `lazyById()` inside the job to avoid loading all records into memory at once. 

      Q03  Does `deselectRecordsAfterCompletion()` work when the action dispatches a job?        Yes. It deselects the checkboxes on the client side as soon as the action closure returns, regardless of whether the actual work is synchronous or queued. It is purely a UI concern. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://msaied.com/articles) 

 [ ![Practical RAG in Laravel: pgvector, Embeddings, and Retrieval Pipelines](https://cdn.msaied.com/411/8d5b164ce43b1c6b9b658b7f72a0c369.png) laravel ai pgvector 

### Practical RAG in Laravel: pgvector, Embeddings, and Retrieval Pipelines

Build a production-ready retrieval-augmented generation pipeline in Laravel using pgvector, OpenAI embeddings,...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 11 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/practical-rag-in-laravel-pgvector-embeddings-and-retrieval-pipelines-1) [ ![Laravel Reverb WebSocket Scaling: Channels, Presence, and Horizontal Deployment](https://cdn.msaied.com/410/2698f47a7daff990e9807996fe0f493c.png) laravel reverb websockets 

### Laravel Reverb WebSocket Scaling: Channels, Presence, and Horizontal Deployment

Move beyond a single Reverb node. Learn how to scale Laravel Reverb horizontally with Redis pub/sub, configure...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 11 Jul 2026     4 min read  

  Read    

 ](https://msaied.com/articles/laravel-reverb-websocket-scaling-channels-presence-and-horizontal-deployment) [ ![Laravel Enum Casts, Backed Enums, and Value Semantics in PHP 8.3](https://cdn.msaied.com/408/3534df365ffb2c8f6c430180bfaba8f1.png) laravel php8.3 enums 

### Laravel Enum Casts, Backed Enums, and Value Semantics in PHP 8.3

PHP 8.3 backed enums combined with Laravel's native enum casting unlock type-safe domain models. Learn how to...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 10 Jul 2026     1 min read  

  Read    

 ](https://msaied.com/articles/laravel-enum-casts-backed-enums-and-value-semantics-in-php-83) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
