Creating a Custom PDF Invoice in Laravel with DomPDF, Images, and CSS Styling

Creating a Custom PDF Invoice in Laravel with DomPDF, Images, and CSS Styling

Creating a Custom PDF Invoice in Laravel with DomPDF, Images, and CSS Styling

Let’s be real, exporting invoices as PDF is still a must-have feature in many business apps. Whether you’re building an e-commerce backend, a freelance project tracker, or a custom CRM, chances are you’ll eventually need to let users download clean, branded invoices.

In this guide, I’ll walk you through how to generate beautiful PDF invoices in Laravel using DomPDF, complete with images (like logos) and custom CSS styles no mess, no guesswork.


Why DomPDF?

Laravel has a handful of PDF generation options from Snappy to TCPDF to mPDF but DomPDF remains one of the most popular thanks to:

  • Simplicity easy to integrate and use
  • Blade view compatibility render your PDFs using regular Laravel Blade templates
  • CSS + inline image support essential for making it look great
  • Free & open-source

If you’re after full control over layout and branding without having to learn a whole new templating language, DomPDF fits the bill perfectly.


Step 1: Install DomPDF via Composer

Let’s start by pulling in the package via the trusted Laravel wrapper:

composer require barryvdh/laravel-dompdf

After installation, Laravel will auto-discover the service provider. But if you’re on an older version, you can add this manually in config/app.php:

'providers' => [
    Barryvdh\DomPDF\ServiceProvider::class,
],

'aliases' => [
    'PDF' => Barryvdh\DomPDF\Facade\Pdf::class,
],

Pro tip: You don’t need to publish the config file unless you need advanced tweaks.


Step 2: Create a Blade Template for Your Invoice

Here’s where it gets fun. Create a dedicated Blade file, e.g., resources/views/invoice.blade.php.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Invoice</title>
    <style>
        body { font-family: sans-serif; font-size: 14px; }
        .header { text-align: center; margin-bottom: 30px; }
        .logo { width: 120px; }
        .table { width: 100%; border-collapse: collapse; }
        .table th, .table td { border: 1px solid #999; padding: 8px; }
        .footer { text-align: center; margin-top: 30px; font-size: 12px; color: #666; }
    </style>
</head>
<body>
    <div class="header">
        <img src="{{ public_path('images/logo.png') }}" class="logo">
        <h2>Invoice #{{ $invoice->id }}</h2>
    </div>

    <table class="table">
        <thead>
            <tr>
                <th>Item</th><th>Qty</th><th>Price</th><th>Total</th>
            </tr>
        </thead>
        <tbody>
            @foreach($invoice->items as $item)
                <tr>
                    <td>{{ $item->name }}</td>
                    <td>{{ $item->qty }}</td>
                    <td>${{ number_format($item->price, 2) }}</td>
                    <td>${{ number_format($item->qty * $item->price, 2) }}</td>
                </tr>
            @endforeach
        </tbody>
    </table>

    <div class="footer">
        Thank you for your business!
    </div>
</body>
</html>

📎 Notes:

  • Use public_path() for images so DomPDF can find them.
  • Stick with inline CSS for best compatibility.

Step 3: Build the Controller to Generate the PDF

Now create a controller method to load the view and convert it to a PDF:

use Barryvdh\DomPDF\Facade\Pdf;
use App\Models\Invoice;

public function download($id)
{
    $invoice = Invoice::with('items')->findOrFail($id);

    $pdf = Pdf::loadView('invoice', compact('invoice'));

    return $pdf->download("invoice-{$invoice->id}.pdf");
}

Simple and clean. You can also use ->stream() if you want it to open in the browser instead.


Step 4: Add the Route

In routes/web.php, register the route like so:

Route::get('/invoice/{id}/download', [InvoiceController::class, 'download']);

Now when you visit /invoice/123/download, it will generate and download the invoice PDF on the fly.


Step 5: Polish the Look with CSS and Branding

Here’s what takes your PDF from “meh” to “wow”:

  • Add your company logo, brand color palette, and typography.
  • Use media queries only if necessary (DomPDF doesn’t support all).
  • Avoid complex layouts keep it table-based.
  • Test your PDF layout in multiple browsers (some fonts may render differently).

Common Pitfalls (And How to Fix Them)

ProblemFix
Image not showingUse public_path() or base64-encoded images
CSS doesn’t applyUse inline CSS and avoid @import or external stylesheets
Fonts look wrongStick to safe fonts (Arial, sans-serif, etc.)
Margins cut offAdd @page rules in <style> or tweak margins manually

Optional: Save PDF to Storage Instead of Download

If you want to store the generated PDF for later, use:

Storage::put("invoices/invoice-{$invoice->id}.pdf", $pdf->output());

Then serve it via URL or attach it to email.


Final Thoughts

DomPDF and Laravel are a perfect match for generating lightweight, styled PDF invoices.

You can build something beautiful without leaving your Laravel comfort zone. Whether you’re making a billing system, e-commerce backend, or admin dashboard, exporting invoices becomes a breeze with this setup.

Just keep your Blade view simple, CSS inline, and assets local and you’re good to go.


Pro Tip:
If you need pixel-perfect PDF rendering or advanced layout features, consider switching to Browsershot or Snappy, but for 80% of use cases, DomPDF is more than enough.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top