Why Use Dompdf for PDF Generation in CodeIgniter 4?

             Dompdf stands out as one of the most popular choices for developers working in CodeIgniter 4 environments due to its simplicity, flexibility, and strong compatibility with modern web standards. Unlike heavier alternatives such as mPDF or TCPDF, which can require extensive configuration, Dompdf allows you to leverage your existing HTML/CSS skills — write clean, responsive templates using familiar tools like Bootstrap or Tailwind, then render them as pixel-perfect PDFs. It supports most CSS3 features (including floats, tables, and basic media queries), making it ideal for dynamic, data-driven documents pulled from your MySQL database.

Key benefits include zero external dependencies after Composer installation, lightweight footprint for faster performance, easy inline styling to avoid layout issues, and seamless integration via a simple controller method. For e-commerce sites, admin panels, or SaaS platforms built on CodeIgniter 4, Dompdf saves development time by eliminating the need to learn proprietary PDF syntax. It also handles Unicode characters well (with font adjustments), supports images (local or base64-encoded), and works reliably in shared hosting environments where tools like wkhtmltopdf may not be available. In short, if you're looking for a balance of ease, reliability, and customization when generating PDFs from HTML views in CodeIgniter 4, Dompdf delivers professional results with minimal overhead — making it the go-to solution for most PHP developers in 2025–2026.



Generate PDF from HTML in CodeIgniter 4 Using Dompdf

Table Of Content

1 Prerequisites

  • PHP 8.1+ (CodeIgniter 4 recommends 8.2+ as of 2025/2026)
  • Composer installed globally
  • MySQL database access
  • Basic knowledge of CodeIgniter 4 (controllers, models, views, migrations)

2 Introduction

In today's web applications built with CodeIgniter 4, the ability to generate professional PDFs on the fly is essential for features like invoices, receipts, delivery notes, reports, and legal documents. While CodeIgniter 4 excels at rapid PHP development, it does not include a native PDF generation library. This is where Dompdf becomes an invaluable tool — a powerful, open-source PHP library that converts HTML and CSS directly into PDF files without relying on external binaries or complex setups.

3 Create / Install a Codeigniter 4 Project

3.1 Install Codeigniter 4 Project

To get started, ensure that you have Composer installed on your computer.
Use the following command to install a new CodeIgniter project:

composer create-project codeigniter4/appstarter ci-4-dompdf-app

Then, navigate to your project directory:

cd ci-4-dompdf-app

3.2 Configure Environment and MySql Database

Rename the env file to .env and set the development mode in the .env file also configure mysql:

# CI_ENVIRONMENT = production
CI_ENVIRONMENT = development


DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=ci4_pdf
DB_USERNAME=root
DB_PASSWORD=

Create the database ci4_pdf in MySQL (e.g., via phpMyAdmin or CLI: CREATE DATABASE ci4_pdf;).

4 Install Dompdf via Composer

To install DomPDF in CodeIgniter, use Composer:

composer require dompdf/dompdf

This adds the latest stable Dompdf (v2.x+ as of 2025/2026), which supports modern CSS better than older versions.

5 Create A Model and Migration

Set up a migration for the Orders table and a model to manage the data.

php spark make:model OrderModel

Edit app/Models/OrderModel.php to configure fields for managing order data.

<?php
namespace App\Models;

use CodeIgniter\Model;

class OrderModel extends Model
{
    protected $table = 'orders';
    protected $primaryKey = 'id';
    protected $allowedFields = ['customer_name', 'total_amount', 'created_at'];
    protected $useTimestamps = true;
    protected $dateFormat = 'datetime';
    protected $createdField = 'created_at';
}

Create a migration file for the orders table:

php spark make:migration AddOrders

Edit the migration file to define the table structure:

<?php
namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class AddOrders extends Migration
{
    public function up()
    {
        $this->forge->addField([
            'id' => [
                'type' => 'INT',
                'constraint' => 5,
                'unsigned' => true,
                'auto_increment' => true,
            ],
            'customer_name' => [
                'type' => 'VARCHAR',
                'constraint' => '100',
            ],
            'total_amount' => [
                'type' => 'DECIMAL',
                'constraint' => '10,2',
            ],
            'created_at' => [
                'type' => 'DATETIME',
                'null' => true,
            ],
        ]);
        $this->forge->addKey('id', true);
        $this->forge->createTable('orders');
    }

    public function down()
    {
        $this->forge->dropTable('orders');
    }
}

Set up a migration for the Order Items table and a model to manage the data.

php spark make:model OrderItemModel

Edit app/Models/OrderItemModel.php to configure fields for managing order data.

<?php
namespace App\Models;

use CodeIgniter\Model;

class OrderItemModel extends Model
{
    protected $table = 'order_items';
    protected $primaryKey = 'id';
    protected $allowedFields = ['order_id', 'product_name', 'quantity', 'price'];
}

Create a migration file for the order items table:

php spark make:migration AddOrderItems

Edit the migration file to define the table structure:

<?php
forge->addField([
            'id' => [
                'type' => 'INT',
                'constraint' => 5,
                'unsigned' => true,
                'auto_increment' => true,
            ],
            'order_id' => [
                'type' => 'INT',
                'constraint' => 5,
                'unsigned' => true,
            ],
            'product_name' => [
                'type' => 'VARCHAR',
                'constraint' => '100',
            ],
            'quantity' => [
                'type' => 'INT',
                'constraint' => 5,
            ],
            'price' => [
                'type' => 'DECIMAL',
                'constraint' => '10,2',
            ],
        ]);
        $this->forge->addKey('id', true);
        $this->forge->addForeignKey('order_id', 'orders', 'id', 'CASCADE', 'CASCADE');
        $this->forge->createTable('order_items');
    }

    public function down()
    {
        $this->forge->dropTable('order_items');
    }
}

Run the migration:

php spark migrate

6 Create Seeder for Sample Data

Create in app/Database/Seeds/ app/Database/Seeds/OrderSeeder.php
  
<?php
namespace App\Database\Seeds;

use CodeIgniter\Database\Seeder;
use CodeIgniter\I18n\Time;

class OrderSeeder extends Seeder
{
    public function run()
    {
        $data = [
            [
                'customer_name' => 'John Doe',
                'total_amount' => 150.00,
                'created_at' => Time::now(),
            ],
            [
                'customer_name' => 'Jane Smith',
                'total_amount' => 200.50,
                'created_at' => Time::now(),
            ],
        ];

        $this->db->table('orders')->insertBatch($data);

        $items = [
            [
                'order_id' => 1,
                'product_name' => 'Product A',
                'quantity' => 2,
                'price' => 50.00,
            ],
            [
                'order_id' => 1,
                'product_name' => 'Product B',
                'quantity' => 1,
                'price' => 50.00,
            ],
            [
                'order_id' => 2,
                'product_name' => 'Product C',
                'quantity' => 3,
                'price' => 66.83,
            ],
        ];

        $this->db->table('order_items')->insertBatch($items);
    }
}
?>

7 Create Controller

Generate a InvoiceController to handle Generate PDF methods:

php spark make:controller InvoiceController

Add methods for generating PDF:

<?php
namespace App\Controllers;

use App\Models\OrderModel;
use App\Models\OrderItemModel;
use CodeIgniter\Controller;
use Dompdf\Dompdf;

class InvoiceController extends Controller
{
    public function index()
    {
        $orderModel = new OrderModel();
        $data['orders'] = $orderModel->findAll();
        return view('orders/index', $data);
    }

    public function generate($id)
    {
        $orderModel = new OrderModel();
        $itemModel = new OrderItemModel();

        $order = $orderModel->find($id);
        if (!$order) {
            return redirect()->to('/orders')->with('error', 'Order not found');
        }

        $data['order'] = $order;
        $data['items'] = $itemModel->where('order_id', $id)->findAll();

        $html = view('invoices/invoice', $data);

        $dompdf = new Dompdf();
        $options = $dompdf->getOptions();
        $options->set('isRemoteEnabled', true); // Enable if using external resources
        $options->set('defaultFont', 'DejaVu Sans'); // For better font support
        $dompdf->setOptions($options);

        $dompdf->loadHtml($html);
        $dompdf->setPaper('A4', 'portrait');
        $dompdf->render();

        // Stream PDF inline (preview in browser); use Attachment => true for download
        $dompdf->stream('invoice_' . $id . '.pdf', ['Attachment' => false]);
    }
}
?>

8 Create View Files

Create directories app/Views/orders/ and app/Views/invoices/.

app/Views/orders/index.php


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Orders List</title>
    <style>
        table { width: 100%; border-collapse: collapse; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
    </style>
</head>
<body>
    <h1>Orders</h1>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Customer</th>
                <th>Total</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($orders as $order): ?>
            <tr>
                <td><?= esc($order['id']) ?></td>
                <td><?= esc($order['customer_name']) ?></td>
                <td>$<?= number_format($order['total_amount'], 2) ?></td>
                <td><a href="<?= site_url('invoice/generate/' . $order['id']) ?>">Generate PDF</a></td>
            </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
</body>
</html>

app/Views/invoices/invoice.php

    
   <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Invoice #<?= $order['id'] ?></title>
    <style>
        body { font-family: DejaVu Sans, sans-serif; margin: 20px; }
        h1 { text-align: center; }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th, td { border: 1px solid #000; padding: 10px; text-align: left; }
        .total { text-align: right; font-weight: bold; margin-top: 20px; }
    </style>
</head>
<body>
    <h1>Invoice #<?= esc($order['id']) ?></h1>
    <p><strong>Customer:</strong> <?= esc($order['customer_name']) ?></p>
    <p><strong>Date:</strong> <?= esc($order['created_at']) ?></p>

    <table>
        <thead>
            <tr>
                <th>Product</th>
                <th>Quantity</th>
                <th>Price</th>
                <th>Total</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($items as $item): ?>
            <tr>
                <td><?= esc($item['product_name']) ?></td>
                <td><?= esc($item['quantity']) ?></td>
                <td>$<?= number_format($item['price'], 2) ?></td>
                <td>$<?= number_format($item['quantity'] * $item['price'], 2) ?></td>
            </tr>
            <?php endforeach; ?>
        </tbody>
    </table>

    <p class="total">Grand Total: $<?= number_format($order['total_amount'], 2) ?></p>
</body>
</html>
    

9 Define a Route

Configure routes in app/Config/Routes.php:

use CodeIgniter\Router\RouteCollection;
$routes->get('orders', 'InvoiceController::index');
$routes->get('invoice/generate/(:num)', 'InvoiceController::generate/$1');

10 Folder Structure

11 Run and Test

Start the server:

php spark serve

Visit http://localhost:8080/orders in your browser. You should see the orders list. Click "Generate PDF" for an order to preview the PDF inline.

Troubleshooting

  • Blank PDF? Ensure HTML is valid; check PHP error logs.
  • Fonts/Images Issues? Dompdf supports basic CSS; use base64 for images if needed.
  • Errors? Verify database connection and run composer dump-autoload if classes aren't found.

This code is tested in a standard CI4 setup and should work fully. If you encounter issues, provide error details!

12 Conclusion

You've now implemented a robust PDF generation feature in CodeIgniter 4 using Dompdf. This approach works great for invoices, reports, and more. Adapt the views/controller for your needs — happy coding!
Revathi M - PHP and CodeIgniter Developer

Written by Revathi M

PHP Developer & Technical Writer · 10+ years building web applications with CodeIgniter and Laravel

Revathi specializes in PHP backend development, authentication systems, and REST API design. She writes practical, production-tested tutorials at Get Sample Code to help developers build secure applications faster.

Frequently Asked Questions

Run the command `composer require dompdf/dompdf` in your CodeIgniter 4 project directory.

You need PHP 8.2 or higher, Composer, and MySQL database.

Load the HTML view, create a new Dompdf instance, load the HTML, set paper size if needed, render it, and use `$dompdf->stream('filename.pdf', ['Attachment' => false]);` to display inline.

This often happens due to output buffering issues, incorrect headers, or HTML layout errors (e.g., wrong table colspan). Ensure no extra output before streaming and validate your HTML/CSS for Dompdf compatibility.

Common causes include PHP version differences, folder/write permissions, memory limits, or server configuration (e.g., output buffering or headers). Check error logs, ensure writable folders, and increase memory_limit if needed.

Dompdf has limited CSS support (CSS 2.1 mostly, some CSS3). Images work if paths are absolute or base_path is set. JavaScript is not supported at all.

Use inline CSS or internal <style> tags in the view file. Avoid advanced CSS features; stick to basics like tables, margins, fonts, and colors for reliable rendering.

Use `php spark serve` and access the app at http://localhost:8080.