HTML to PDF, the easy path
So far in this track you have built pages one call at a time. Many documents are quicker to describe as markup, the tag-based text format used for web pages. In this tutorial you hand NextPDF some Hypertext Markup Language (HTML), and the engine draws the page for you.
What you will build
Section titled “What you will build”A one-page report rendered from a single HTML string. It has a colored heading, a short paragraph, and a table with a totals row. You style it with Cascading Style Sheets (CSS), the rule language that controls how markup looks. In the earlier tutorials you used the fluent Application Programming Interface (API), the chained method calls. Here you describe the layout in markup instead, and the same engine renders it.
Step 1: Render a styled report from HTML
Section titled “Step 1: Render a styled report from HTML”Create a file named 01-html.php in your project folder, next to vendor.
Paste in this complete script:
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
@mkdir(__DIR__ . '/out');
$document = Document::createStandalone();$document->setTitle('Monthly reading report');$document->addPage();
$html = <<<'HTML'<h1 style="color: #1E3A8A;">Monthly reading report</h1>
<p>This report was rendered from <strong>HTML</strong> with inline<em>CSS</em>. The table below lists two books and their page counts.</p>
<table border="1" cellpadding="5" cellspacing="0" style="width: 100%;"> <thead> <tr style="background-color: #1E3A8A; color: #FFFFFF;"> <th style="width: 55%;">Title</th> <th style="width: 20%; text-align: center;">Format</th> <th style="width: 25%; text-align: right;">Pages</th> </tr> </thead> <tbody> <tr> <td>The Paper Trail</td> <td style="text-align: center;">Hardcover</td> <td style="text-align: right;">312</td> </tr> <tr style="background-color: #F8FAFC;"> <td>Ink and Bytes</td> <td style="text-align: center;">Paperback</td> <td style="text-align: right;">248</td> </tr> </tbody> <tfoot> <tr style="font-weight: bold;"> <td colspan="2" style="text-align: right;">Total pages:</td> <td style="text-align: right;">560</td> </tr> </tfoot></table>HTML;
$document->writeHtml($html);
$document->save(__DIR__ . '/out/reading-report.pdf');
echo "Wrote out/reading-report.pdf\n";Run the script from the project folder:
php 01-html.phpYou should see one line of output:
Wrote out/reading-report.pdfOpen out/reading-report.pdf in any Portable Document Format (PDF) viewer.
The heading is dark blue, and the table header row is filled with the same
color.
What just happened
Section titled “What just happened”@mkdir(__DIR__ . '/out');creates the output folder. The@sign hides the warning when the folder already exists, so repeat runs stay quiet.Document::createStandalone(),setTitle(), andaddPage()work exactly as in the earlier tutorials. Switching to markup changes nothing about document setup.writeHtml()reads your string once, from top to bottom, and draws each element at the current position. Headings and paragraphs become styled text. The table becomes measured rows of bordered cells.- The inline
styleattributes carry the CSS. The engine understands common properties such ascolor,background-color,text-align, andwidth. - No browser and no extra software are involved. The pipeline is plain PHP inside the engine, so the script runs wherever your Composer install runs.
The engine supports a practical subset of HTML and CSS, not everything a browser accepts. Anything outside that subset is skipped quietly rather than raising an error. The CSS support matrix records exactly what is covered. For a deeper walk through this pipeline, see Render HTML to a PDF page.
When to use HTML and when to use the fluent API
Section titled “When to use HTML and when to use the fluent API”Both routes run on the same engine, so pick whichever fits the document.
- Choose
writeHtml()when the document reads like a web page: headings, paragraphs, lists, and tables. Markup is faster to write and easier for teammates to edit. - Choose the fluent API when you need exact placement, such as fixed positions or precisely measured cells. Markup gives you flow; the fluent calls give you control.
- Check the CSS support matrix before relying on a property. When a style is not covered, build that part with fluent calls instead.
The safety boundary
Section titled “The safety boundary”Real HTML often comes from outside your code, for example from a form or a database. Treat it as untrusted input, and validate or clean it before rendering. By default, the built-in pipeline runs no scripts and fetches no remote resources. That default keeps the renderer conservative even when the markup is not. If you need browser-grade rendering options, see Choose your path.
If something went wrong
Section titled “If something went wrong”Failed to open stream: No such file or directoryusually means the script cannot findvendor/autoload.php. Run it from the folder where you ran Composer.- A missing style is usually a property outside the supported subset. The engine skips what it does not support instead of failing. Compare your markup against the CSS support matrix.
- An exception while rendering names the exact problem. Look it up in the rendering and input/output errors reference.
For anything else, start with the troubleshooting guide.
You can now build documents call by call and from markup. Finish the track with Where to go next. It maps the cookbook, the reference, and the guides you will use after this track.