Filament v3 Custom Actions: Bulk, Table &amp; Header | 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)    Laravel Filament v3 Custom Actions: Bulk, Table, and Header Actions Done Right        On this page       1. [  Filament v3 Custom Actions: Bulk, Table, and Header Actions Done Right ](#filament-v3-custom-actions-bulk-table-and-header-actions-done-right)
2. [  1. Extracting Actions Into Dedicated Classes ](#1-extracting-actions-into-dedicated-classes)
3. [  2. Bulk Actions That Dispatch Batched Jobs ](#2-bulk-actions-that-dispatch-batched-jobs)
4. [  3. Header Actions With Service Injection ](#3-header-actions-with-service-injection)
5. [  4. Guarding Actions With Visibility vs. Authorization ](#4-guarding-actions-with-visibility-vs-authorization)
6. [  5. Passing Extra Data Through mountUsing and form ](#5-passing-extra-data-through-codemountusingcode-and-codeformcode)
7. [  Takeaways ](#takeaways)

  ![Laravel Filament v3 Custom Actions: Bulk, Table, and Header Actions Done Right](https://cdn.msaied.com/502/ff034ec2bd69cdc8e56eced7a83882a3.png)

  #filament   #laravel   #filament-actions   #php  

 Laravel Filament v3 Custom Actions: Bulk, Table, and Header Actions Done Right 
================================================================================

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

       Table of contents

1. [  01   Filament v3 Custom Actions: Bulk, Table, and Header Actions Done Right  ](#filament-v3-custom-actions-bulk-table-and-header-actions-done-right)
2. [  02   1. Extracting Actions Into Dedicated Classes  ](#1-extracting-actions-into-dedicated-classes)
3. [  03   2. Bulk Actions That Dispatch Batched Jobs  ](#2-bulk-actions-that-dispatch-batched-jobs)
4. [  04   3. Header Actions With Service Injection  ](#3-header-actions-with-service-injection)
5. [  05   4. Guarding Actions With Visibility vs. Authorization  ](#4-guarding-actions-with-visibility-vs-authorization)
6. [  06   5. Passing Extra Data Through mountUsing and form  ](#5-passing-extra-data-through-codemountusingcode-and-codeformcode)
7. [  07   Takeaways  ](#takeaways)

 Filament v3 Custom Actions: Bulk, Table, and Header Actions Done Right
----------------------------------------------------------------------

Filament ships with a generous set of built-in actions, but production apps quickly outgrow them. You need bulk operations that dispatch jobs, header actions that resolve services from the container, and row-level actions that enforce policy before they run. This article shows concrete patterns for each.

---

### 1. Extracting Actions Into Dedicated Classes

Inlining action logic inside `getTableActions()` works for demos. For anything real, extract to a class:

```php
// app/Filament/Actions/ArchiveOrderAction.php
namespace App\Filament\Actions;

use App\Jobs\ArchiveOrderJob;
use App\Models\Order;
use Filament\Tables\Actions\Action;

class ArchiveOrderAction
{
    public static function make(): Action
    {
        return Action::make('archive')
            ->label('Archive')
            ->icon('heroicon-o-archive-box')
            ->requiresConfirmation()
            ->authorize(fn (Order $record) => auth()->user()->can('archive', $record))
            ->action(function (Order $record): void {
                dispatch(new ArchiveOrderJob($record->id));
            })
            ->successNotificationTitle('Order queued for archiving');
    }
}

```

Register it in your resource:

```php
public function getTableActions(): array
{
    return [
        ArchiveOrderAction::make(),
        EditAction::make(),
    ];
}

```

The `authorize()` callback receives the resolved model, so policy checks stay close to the action without touching the resource.

---

### 2. Bulk Actions That Dispatch Batched Jobs

Bulk actions receive a `Collection` of selected records. Pair them with `Bus::batch()` for reliable fan-out:

```php
use Filament\Tables\Actions\BulkAction;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Bus;

BulkAction::make('reprocess')
    ->label('Reprocess Selected')
    ->icon('heroicon-o-arrow-path')
    ->requiresConfirmation()
    ->deselectRecordsAfterCompletion()
    ->action(function (Collection $records): void {
        $jobs = $records->map(
            fn ($record) => new ReprocessOrderJob($record->id)
        )->all();

        Bus::batch($jobs)
            ->name('reprocess-orders')
            ->allowFailures()
            ->dispatch();
    });

```

`allowFailures()` means one bad record does not abort the entire batch — critical when operating on hundreds of rows.

---

### 3. Header Actions With Service Injection

Header actions live outside the table loop, making them ideal for operations that need infrastructure services:

```php
use Filament\Actions\Action;
use App\Services\ReportExporter;

protected function getHeaderActions(): array
{
    return [
        Action::make('export')
            ->label('Export CSV')
            ->action(function (ReportExporter $exporter): \Symfony\Component\HttpFoundation\StreamedResponse {
                return $exporter->streamCsv(
                    $this->getTableQuery()->get()
                );
            }),
    ];
}

```

Filament resolves the `ReportExporter` from the service container automatically via the `action()` closure's type-hint — no manual `app()` call needed.

---

### 4. Guarding Actions With Visibility vs. Authorization

Two separate concerns are often conflated:

- **`visible()`** — controls whether the action renders at all (UI concern).
- **`authorize()`** — throws a 403 if the action is invoked without permission (security concern).

Always set both:

```php
Action::make('refund')
    ->visible(fn () => auth()->user()->hasRole('billing'))
    ->authorize(fn (Order $record) => auth()->user()->can('refund', $record))
    ->action(fn (Order $record) => $record->issueRefund());

```

Relying only on `visible()` is a security hole — a crafty user can POST the action directly.

---

### 5. Passing Extra Data Through `mountUsing` and `form`

When an action needs user input before executing, combine `form()` with `mountUsing()` to pre-populate fields:

```php
Action::make('reschedule')
    ->form([
        DateTimePicker::make('scheduled_at')->required(),
    ])
    ->mountUsing(fn (ComponentContainer $form, Order $record) =>
        $form->fill(['scheduled_at' => $record->scheduled_at])
    )
    ->action(fn (array $data, Order $record) =>
        $record->update(['scheduled_at' => $data['scheduled_at']])
    );

```

---

### Takeaways

- Extract actions to dedicated classes early; inline closures do not scale.
- Use `Bus::batch()` inside bulk actions for reliable, observable fan-out.
- Header action closures support full container injection via type-hints.
- Always pair `visible()` with `authorize()` — they are not interchangeable.
- `mountUsing()` lets you pre-fill action forms from the current record state.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-filament-v3-custom-actions-bulk-table-and-header-actions-done-right&text=Laravel+Filament+v3+Custom+Actions%3A+Bulk%2C+Table%2C+and+Header+Actions+Done+Right) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-filament-v3-custom-actions-bulk-table-and-header-actions-done-right) 

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

  3 questions  

     Q01  Can I reuse a custom action class across multiple Filament resources?        Yes. Because the action is a plain static factory method returning an `Action` instance, you can call `ArchiveOrderAction::make()` from any resource's `getTableActions()` or `getHeaderActions()` without duplication. 

      Q02  How do I test that an action dispatches the correct job?        Use `Queue::fake()` before triggering the action in your Pest test, then assert with `Queue::assertPushed(ReprocessOrderJob::class)`. Filament's `livewire()-&gt;callTableAction()` helper fires the full action lifecycle including your closure. 

      Q03  What is the difference between `action()` and `successRedirectUrl()` in a header action?        `action()` is the handler closure that runs your business logic. `successRedirectUrl()` is an optional follow-up that redirects the user after a successful action — useful after creating a related resource or triggering an export. 

  Continue reading

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

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

 [ ![PhpStorm 2026.2 Released: Laravel Tool Window, PHP 8.5 Pipe Operator, and AI Agents](https://cdn.msaied.com/505/151a0bba66cc27064e090e69e55d7c92.png) PhpStorm JetBrains PHP 8.5 

### PhpStorm 2026.2 Released: Laravel Tool Window, PHP 8.5 Pipe Operator, and AI Agents

PhpStorm 2026.2 ships a dedicated Laravel tool window with Artisan, error logs, and Laravel Cloud tabs, plus P...

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

 3 Aug 2026     3 min read  

  Read    

 ](https://msaied.com/articles/phpstorm-20262-released-laravel-tool-window-php-85-pipe-operator-and-ai-agents) [ ![Laravel Doctor: Diagnose Your Laravel App With One Artisan Command](https://cdn.msaied.com/504/d72224689abc7b396bce187535008272.png) Laravel Artisan Health Checks 

### Laravel Doctor: Diagnose Your Laravel App With One Artisan Command

Laravel Doctor is a first-party package announced at Laracon US 2026 that adds an `artisan doctor` command to...

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

 3 Aug 2026     4 min read  

  Read    

 ](https://msaied.com/articles/laravel-doctor-diagnose-your-laravel-app-with-one-artisan-command) [ ![Livewire v4.3.5 Released: Fix for SFC Detection with PHP Attribute Array Arguments](https://cdn.msaied.com/503/9678ed8dbf5d7a6f4f19ca7694cf241b.png) Livewire Laravel PHP 

### Livewire v4.3.5 Released: Fix for SFC Detection with PHP Attribute Array Arguments

Livewire v4.3.5 ships a targeted bug fix for Single File Component (SFC) detection when PHP attributes contain...

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

 3 Aug 2026     2 min read  

  Read    

 ](https://msaied.com/articles/livewire-v435-released-fix-for-sfc-detection-with-php-attribute-array-arguments) 

   [  ![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)
