Generating a PDF from an HTML/Blade view in Laravel — an invoice, a report, a certificate — is most commonly handled through barryvdh/laravel-dompdf, a wrapper around the DomPDF library, with one important limitation worth knowing upfront.
Installing the package
composer require barryvdh/laravel-dompdf
Generating a PDF from a Blade view
use Barryvdh\DomPDF\Facade\Pdf;
public function downloadInvoice(Order $order)
{
$pdf = Pdf::loadView('invoices.pdf', compact('order'));
return $pdf->download('invoice-'.$order->id.'.pdf');
}
The Blade view, styled with plain inline or embedded CSS
Invoice #{{ $order->id }}
@foreach ($order->items as $item)
{{ $item->name }}
{{ $item->price }}
@endforeach
Displaying the PDF in the browser instead of downloading it
return $pdf->stream('invoice.pdf');
stream() sends the PDF with headers that let the browser display it inline (if the browser supports inline PDF viewing) — download() instead forces a save-to-disk download prompt; the choice between them depends purely on the desired user experience for viewing versus saving the document.
Saving the generated PDF to disk instead of sending it to the browser
$pdf = Pdf::loadView('invoices.pdf', compact('order'));
$pdf->save(storage_path('app/invoices/invoice-'.$order->id.'.pdf'));
Setting paper size and orientation
$pdf = Pdf::loadView('reports.summary', compact('data'))
->setPaper('a4', 'landscape');
The critical limitation: DomPDF is not a real browser
DomPDF renders HTML/CSS using its own internal layout engine, not an actual browser rendering engine like Chromium — modern CSS features (Flexbox, CSS Grid, many custom properties) are only partially supported or not supported at all, which is exactly why a layout that looks correct in a real browser can appear noticeably broken or different once rendered as a PDF; simple table-based or basic block/inline layouts are the safest, most reliable approach for DomPDF specifically.
A more accurate alternative for complex layouts: a headless browser
// Using a package like spatie/browsershot, which drives headless Chrome
Browsershot::html($html)->savePdf(storage_path('app/invoice.pdf'));
For a genuinely complex, modern CSS-heavy layout that needs to render pixel-accurately, a headless-browser-based tool (like spatie/browsershot, which actually drives Chrome under the hood) produces meaningfully more accurate results than DomPDF — at the cost of a heavier server dependency (an actual Chrome/Chromium binary) and generally slower generation time per PDF.
Embedding an image in the PDF
 }})
Using an absolute server filesystem path (via public_path()) rather than a normal web URL is necessary for DomPDF to reliably embed a local image — it doesn't always resolve a relative or web-based URL path the same way a real browser would when rendering the HTML into a PDF.