Dompdf alternative for PHP
Dompdf alternative for PHP. Dompdf lacks flexbox and grid and slows on big tables. Compare mPDF and Browsershot, or render Chrome-quality PDFs.
Dompdf is the default answer for "HTML to PDF in PHP". It's pure PHP, installs with Composer and works well for simple documents. Teams often hit a wall when the HTML uses modern CSS or gets long.
This page covers the usual pain points, the main PHP alternatives, and how to call a Chrome-based API from PHP and Laravel.
Quick answer. Send your HTML to a hosted Chromium API and get the PDF back:
curl -X POST https://html-pdf.com/v1/pdf \
-H "Authorization: Bearer $HTML_PDF_KEY" \
-H "Content-Type: application/json" \
-d '{"html": "<div style=\"display:flex\"><h1>Invoice #042</h1></div>"}' \
-o invoice.pdf
Common Dompdf problems
These are the issues that usually push teams away from Dompdf.
- No flexbox or grid. Dompdf implements its own layout engine, mostly CSS 2.1 with some CSS3. Layouts built with
display: flexordisplay: gridcollapse into stacked blocks. - Limited CSS3. Many newer properties and selectors are partial or missing, so a template that looks right in Chrome looks different in the PDF.
- Big tables are slow. Long tables use a lot of memory and render time, and can hit PHP's
memory_limitormax_execution_time. - Fonts take setup. Custom fonts need to be registered or loaded with
@font-faceand a writable font cache. Missing glyphs show up as?. - No JavaScript. Charts drawn with Chart.js or similar never render.
PHP alternatives
Here are the three main options PHP developers move to.
mPDF is also pure PHP. It handles headers, footers, right-to-left and CJK text well. It also uses its own layout engine, so flexbox and grid have the same problem.
Spatie Browsershot drives real headless Chrome through Puppeteer, so CSS and JavaScript render like the browser. The cost is infrastructure. You need Node.js, Puppeteer, a Chrome binary and Chrome's system libraries on every server, which is awkward on shared hosting, slim Docker images and some serverless setups.
A hosted Chrome API gives Browsershot-style output with just an HTTP call from PHP.
Comparison
This table compares the four options at a glance.
| Dompdf | mPDF | Browsershot | html-pdf.com API | |
|---|---|---|---|---|
| Engine | PHP layout engine | PHP layout engine | Headless Chrome | Headless Chromium (hosted) |
| Flexbox / grid | No | No | Yes | Yes |
| JavaScript | No | No | Yes | Yes |
| Server requirements | PHP extensions | PHP extensions | Node + Puppeteer + Chrome | None (HTTP) |
| Works offline | Yes | Yes | Yes | No |
| Cost | Free (LGPL) | Free (GPL) | Free (MIT) + servers | 1 credit per page |
When Dompdf is the better choice
Dompdf is still the right tool in a few cases.
- Simple, table-based documents (basic invoices, letters) that you design for Dompdf from the start.
- Environments without outbound network access, or where HTML must never leave your server.
- Low volume, where adding a paid service isn't worth it.
If your templates already work in Dompdf and you're happy with them, there's no reason to switch.
Calling a Chrome API from PHP
These examples show how to render a PDF from plain PHP and from Laravel.
Plain PHP (cURL)
<?php
$html = '<div style="display:flex;justify-content:space-between"><h1>Invoice #042</h1><p>Total: $120.00</p></div>';
$ch = curl_init('https://html-pdf.com/v1/pdf');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 40,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('HTML_PDF_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'html' => $html,
'format' => 'A4',
'landscape' => true,
'margin' => '15mm',
]),
]);
$pdf = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
throw new RuntimeException("PDF failed ($status): $pdf");
}
file_put_contents('invoice.pdf', $pdf);
Laravel (Http client)
use Illuminate\Support\Facades\Http;
Route::get('/invoices/{invoice}/pdf', function (App\Models\Invoice $invoice) {
$html = view('invoices.pdf', ['invoice' => $invoice])->render();
$response = Http::withToken(env('HTML_PDF_KEY'))
->timeout(40)
->post('https://html-pdf.com/v1/pdf', [
'html' => $html,
'format' => 'A4',
'margin' => '15mm',
'max_pages' => 20,
]);
abort_unless($response->successful(), 502, 'PDF generation failed');
return response($response->body(), 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => "inline; filename=\"invoice-{$invoice->id}.pdf\"",
]);
});
In a real app, read the key through config() rather than env() so it still works after php artisan config:cache. Your Blade views can keep using Tailwind, flexbox or grid.
Images and fonts must use absolute https:// URLs or data URIs, because the renderer can't reach localhost.
Mapping Dompdf calls
This table shows the html-pdf.com option for each common Dompdf call.
| Dompdf | html-pdf.com |
|---|---|
$dompdf->setPaper('A4', 'landscape') |
'format' => 'A4', 'landscape' => true |
setPaper('letter', 'portrait') |
'format' => 'Letter' |
setPaper([0, 0, 612, 1008]) (points) |
'width' => '8.5in', 'height' => '14in' |
isRemoteEnabled |
Not needed; public https:// assets load |
$dompdf->stream('file.pdf') |
'filename' => 'file.pdf' and return the body |
$canvas->page_text(...) page numbers |
footer_html with pageNumber / totalPages |
@page { margin: ... } |
Keep it with prefer_css_page_size, or use margin |
For page numbers, add a footer and leave room for it with a bottom margin.
'margin' => ['top' => '15mm', 'right' => '12mm', 'bottom' => '20mm', 'left' => '12mm'],
'footer_html' => '<div style="font-size:9px;width:100%;text-align:center">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>',
Or skip the server
html-pdf.com lets you get Chrome-quality PDFs without installing Node, Puppeteer or Chrome on your PHP servers. It's a hosted HTML and URL to PDF API on headless Chromium.
Send POST https://html-pdf.com/v1/pdf with a Bearer key and {"html": "..."} or {"url": "https://..."}. You get back a PDF with selectable text, as binary, base64 or a 24-hour link.
1 credit = 1 PDF page. You get 100 free credits once, then packs run from $10 for 1,000 pages to $250 for 50,000 ($0.01 to $0.005 per page), and purchased credits never expire. A remote MCP server is also available for AI assistants.
FAQ
What is the best Dompdf alternative for flexbox and grid?
A Chrome-based renderer. Browsershot runs headless Chrome on your own server, and html-pdf.com runs Chromium as a hosted API, so flexbox, grid and JavaScript render like the browser. mPDF has the same layout limits as Dompdf.
How do I add page numbers when moving off Dompdf?
Replace $canvas->page_text(...) with a footer_html that contains <span class="pageNumber"></span> and <span class="totalPages"></span>. Leave a bottom margin so the footer has room.
Is there a free Dompdf alternative?
mPDF and Browsershot are free open-source libraries, though Browsershot needs Chrome on your servers. html-pdf.com gives you 100 free credits once with no card, and 1 credit is 1 PDF page.
Can I use html-pdf.com from Laravel?
Yes. Render your Blade view to HTML and post it to https://html-pdf.com/v1/pdf with Http::withToken(...), as in the example above.
Get a free API key · API docs · HTML to PDF in PHP · HTML to PDF in Laravel · Page breaks
