Filament: Export Record to PDF - Two Ways

Exporting data to PDF is a very common feature. This tutorial will show how to do it in the Filament admin panel: we will export a single record to PDF using Blade View and barryvdh/laravel-dompdf package.

PDF export action button

We will use the official Filament demo project for the demo code, adding a PDF download to the OrderResource. The source code for the original demo it can be found on the GitHub here.


Method 1: Filament Action

First, let's see how we can export into a PDF from Filament action.

app/Filament/Resources/Shop/OrderResource.php:

use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Facades\Blade;
 
class OrderResource extends Resource
{
// ...
 
public static function table(Table $table): Table
{
return $table
->columns([
// ...
])
->filters([
// ...
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\Action::make('pdf')
->label('PDF')
->color('success')
->icon('heroicon-s-download')
->action(function (Model $record) {
return response()->streamDownload(function () use ($record) {
echo Pdf::loadHtml(
Blade::render('pdf', ['record' => $record])
)->stream();
}, $record->number . '.pdf');
}),
])
->bulkActions([
// ...
]);
}
 
// ...
}

The first import code here is what we return. This response comes from the Livewire where first we pass the content and the second parameter is the filename.

For the PDF content, we use the loadHTML method from the barryvdh/laravel-dompdf package, and we stream it. To get the HTML we are using the Blade facade to render the Blade file and passing the data.

After this, we have a PDF button in the Orders list.

PDF export action button

Now, in the Blade file, you can add any data you need about the record. I called this View pdf.blade.php.

resources/views/pdf.blade.php:

<div>Number: {{ $record->number }}</div>
<div>Customer: {{ $record->customer->name }}</div>
<div>Status: {{ $record->status }}</div>
<div>Total price: {{ $record->total_price }}</div>
<div>Order Date: {{ $record->created_at }}</div>

After clicking the PDF button, the PDF will be downloaded with basic information about the order.

PDF view


Method 2: Using Controller and Route

Here's an alternative approach. First, we need a Controller and a Route.

php artisan make:controller PdfController

routes/web.php:

use App\Http\Livewire\Form;
use App\Http\Controllers\PdfController;
 
\Illuminate\Support\Facades\Route::get('form', Form::class);
 
Route::get('pdf/{order}', PdfController::class)->name('pdf');

In the Controller, we can generate the PDF from the View using loadView method from the barryvdh/laravel-dompdf package and chaining it to download.

app/Http/Controllers/PdfController.php:

use App\Models\Shop\Order;
use Barryvdh\DomPDF\Facade\Pdf;
 
class PdfController extends Controller
{
public function __invoke(Order $order)
{
return Pdf::loadView('pdf', ['record' => $order])
->download($order->number. '.pdf');
}
}

We need to call this Route in the Filament action.

app/Filament/Resources/Shop/OrderResource.php:

class OrderResource extends Resource
{
// ...
 
public static function table(Table $table): Table
{
return $table
->columns([
// ...
])
->filters([
// ...
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\Action::make('pdf')
->label('PDF')
->color('success')
->icon('heroicon-o-document-download')
->url(fn (Order $record) => route('pdf', $record))
->openUrlInNewTab(),
])
->bulkActions([
// ...
]);
}
 
// ...
}

And that's it. After clicking the PDF button, it will open the URL in a new tab and will download the generated PDF file.


If you want more Filament examples, you can find more real-life projects on our FilamentExamples.com.

avatar

Hello, First method deletes the template view for pdf from resource. Why ?

avatar

deleteCachedView isn't needed

avatar

Yeah i know but from "Also, we don't need this cached View, so we are setting it to be deleted." It means cached view. So why it deletes my orginal template from resources/views/pdf.blade.php ?

avatar

It was a mistake. Updated text.

avatar

This is a very helpful topic. In my case I use method 1: Filament Action. How can I use JavaScript in loaded Blade? I have this simple Blade template:

Test PDF

<script type="text/javascript"> function insertHtml() { document.getElementById("demo").innerHTML = "I have changed!"; } insertHtml() </script>

When I execute the code explained in Method 1 in the generated PDF is outputted “Test PDF” instead “I have changed!”. Where is my mistake and how to solve this problem? Thank you.

avatar

Test PDF

<script type="text/javascript"> function insertHtml() { document.getElementById("demo").innerHTML = "I have changed!"; } insertHtml() </script>
avatar

I guess then you cant? Would would you even want to use it?

avatar

I want to use JavaScript to insert dynamically HTML using insertAdjacentHTML() but DomPdf does not take in account the JavaScript contained in the blade Template. And also I don’t know why I can’t paste in the comments the source of the Blade.

avatar

If its dompdf thing cant help

avatar

OK. Thank you.

avatar

How to view pdf in browser without download it?

avatar

Change ->download(...) to ->stream(...) and it should work

avatar

Nice. It work. Tq

avatar

Hello and if I would like to open a modal with the pdf file what could you suggest me?

avatar

If you want a modal with the PDF, you do need:

https://laraveldaily.com/post/filament-table-row-action-view-modal-infolist

Or in other words, your modal has to be an infolist and there you have to create a custom HTML component (ViewEntry) to load the PDF in an iframe. There is no other way at this point

avatar

How can i pass the pdf to the ViewEntry? viewData does not accept a closure?

avatar

With filamentphp v3, Laravel 10.34.2, PHP 8.2.0 I get the following error: Unable to prepare route [pdf/{record}] for serialization. Another route has already been assigned name [pdf]. in web.php: Route::get('pdf/{record}', PdfController::class)->name('pdf');

In PdfResourse.php Action::make(('Pdf')) ->icon('heroicon-o-printer') ->url(fn (Invoices $record) => route('pdf', $record)) ->openUrlInNewTab(),**

How do I resolve the routing error? *

avatar
Michal “Spil” Korol

if its only name issue, just change route name ->name('another_pdf')

also refactor your code where you use routes by names

avatar

I have used method 1. How can I add a custom CSS and JS file to my pdf.blade.php template?

avatar

You can't add js and you shouldn't. As for CSS write a custom styles

avatar

How do I customize the appearnace of the exported PDF?

For example: I wish to add my company logo and move around some of the locations of each field. A result would be a nice looking customer facing Invoice.

avatar

Since this is a view based PDF - you have to modify the view template itself. Anything you put inside of it - will be in your PDF.

We don't have a tutorial for this, as it is as simple as creating the HTML content

avatar

Does this also work for table header actions, or only for row actions?

I need to export/print a pdf of an admin panel resource table.

avatar

This should work on header action too

avatar

It would be interesting to see how everyone does this not on a record but on the resultant table in filament. IE if you have a table that's the result of search or filter, how can you STREAM that to a PDF - Thanks for thoughts

avatar

You would get selected records from the table component. Plenty of such questions on the filament discord, should check their

avatar

Thanks

avatar

Using the controller method, how can I make sure that the route is protected with the same authentication as the Filament portal? That seems like something very important that should be implemented.

avatar

It's laravel. Add authorization in whate way you want

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 67 courses (1172 lessons, total 43 h 18 min)
  • 89 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent New Courses