ToolUp.Reporting.HtmlPdf 0.22.0

Prefix Reserved
dotnet add package ToolUp.Reporting.HtmlPdf --version 0.22.0
                    
NuGet\Install-Package ToolUp.Reporting.HtmlPdf -Version 0.22.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ToolUp.Reporting.HtmlPdf" Version="0.22.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ToolUp.Reporting.HtmlPdf" Version="0.22.0" />
                    
Directory.Packages.props
<PackageReference Include="ToolUp.Reporting.HtmlPdf" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ToolUp.Reporting.HtmlPdf --version 0.22.0
                    
#r "nuget: ToolUp.Reporting.HtmlPdf, 0.22.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ToolUp.Reporting.HtmlPdf@0.22.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ToolUp.Reporting.HtmlPdf&version=0.22.0
                    
Install as a Cake Addin
#tool nuget:?package=ToolUp.Reporting.HtmlPdf&version=0.22.0
                    
Install as a Cake Tool

ToolUp.Reporting.HtmlPdf

HTML→PDF rendering sub-companion for ToolUp.Reporting: render an HTML report template — print CSS respected — to paginated PDF via Playwright / headless Chromium, through the standard IReportRenderer / RendererRegistry path.

This is the second PDF road beside the (deferred, QuestPDF-shaped) code-layout sub-companion, and they serve different template authors: QuestPDF templates are code layouts; this renderer takes the HTML your HtmlRenderer templates already are and prints them. @page size and margins, page breaks, and header/footer bands all behave as the CSS says.

Quick start

open ToolUp.Reporting
open ToolUp.Reporting.HtmlPdf

// Compose time — register beside the zero-dep defaults:
let registry =
    ReportingCompose.buildDefaultRegistry ()
    |> ReportingCompose.withRenderer (HtmlPdfReportRenderer.create ())

// Template: Format = Pdf, body = print-CSS HTML with {{placeholders}}.
let template = {
    Id = "quarterly-report"
    DisplayName = "Quarterly report"
    Format = Pdf
    Body = File.ReadAllBytes "quarterly.html"
    Placeholders = [ { Key = "period"; DisplayName = "Period"; Kind = Text; Required = true } ]
    Version = 1
}

// Render through the standard path — PDF bytes out.
let! result = registry.TryResolve(Pdf).Value.Render(template, Map [ "period", TextValue "Q2 2026" ])

Format registration (how this coexists with HtmlRenderer)

This renderer claims TemplateFormat.Pdf. A template targeting it declares Format = Pdf and carries a print-CSS HTML body — exactly the "renderer-specific shape" ReportTemplate.Body reserves for Pdf. The shipped HtmlRenderer keeps Html (HTML in, HTML out), so the registry resolves the two unambiguously. A future QuestPDF renderer would also claim Pdf with a different body shape; RendererRegistry's last-registered-wins makes that a per-deployment choice.

Placeholder semantics are inherited wholesale — the body is filled through the shipped HtmlRenderer (same escaping, _raw bypass, Table<table>, Image → data-URL <img>, which prints with no network fetch) and then printed.

Defaults are print-CSS-wins: a template that declares @page { size: A5; margin: 15mm } renders exactly so (PreferCssPageSize defaults true), page breaks honour page-break-* / break-* rules, and PrintBackground is on. PdfRenderOptions covers templates that don't speak for themselves: paper Format, Margins, Scale, and Chromium HeaderTemplate / FooterTemplate bands (with the pageNumber / totalPages / date / title span classes).

Browser lifecycle

Chromium launches lazily on the first render (composing the renderer costs nothing — GP 13), stays warm across renders (launch is seconds-class; a warm render is milliseconds-class), closes after BrowserIdleTimeout (default 5 minutes), and relaunches transparently after a crash: a render against a dead browser fails as a typed RenderError (never a hung Async) and the next render brings a fresh instance up.

Deployment-image implications (read before composing)

This sub-companion is for deployments that accept a browser in the image. If yours can't, use the QuestPDF road instead — that is the entire trade between the two PDF renderers.

  • Chromium must exist in the container. The NuGet package ships the driver, not the browser. Either run playwright install chromium (or playwright install --with-deps chromium on Debian/Ubuntu to pull the OS libraries) during image build, or base the runtime stage on the official mcr.microsoft.com/playwright/dotnet image which has both preinstalled.
  • Image-size cost: headless Chromium plus its OS dependencies adds roughly 300–400 MB to a Linux image. Budget for it deliberately.
  • PLAYWRIGHT_BROWSERS_PATH: set it when you install browsers into a custom location (e.g. a shared layer) so the driver finds them at runtime; otherwise the default per-user cache path applies.
  • Sandbox posture: Chromium's sandbox cannot run as root without user namespaces. Prefer a non-root container user (the official image does this). Only if your platform forces root, pass LaunchArgs = [ "--no-sandbox" ] — and treat that as accepting reduced process isolation for whatever HTML you render.
  • Trust posture: templates are operator-authored. This sub-companion does no HTML sanitisation — do not feed it untrusted end-user HTML, particularly in a --no-sandbox container.

Testing

The contract + fixture pack lives in src/Reporting/HtmlPdf.Tests/ and is browser-gated: on a checkout without a Playwright-managed Chromium the rendering arms report Pending, not Failed (install with pwsh <test-output>/playwright.ps1 install chromium to run them). Validation error paths and the strip-imports proof run everywhere — the browser is lazy, so no test needs it until something actually prints.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.22.0 35 8/27/2026
0.21.0 49 8/26/2026
0.20.1 91 8/20/2026
0.20.0 107 8/19/2026