TerraFluent.Html.Reporting · v1.1.1

Print-ready HTML reports, no PDF engine required

A fluent, dependency-free library for paginated reports with fixed page sizes, measured content flow, and self-contained HTML/CSS — opens in any browser, prints to PDF.

NuGet version NuGet downloads MIT license
dotnet add package TerraFluent.Html.Reporting
Quick start

A complete report in one fluent chain

Fixed page geometry, a repeating header, a page-numbered footer, and measured content flow — then render to a string or straight to a file. Open the result in a browser, or print/save it as PDF.

  • A4, Letter, Legal, portrait/landscape, or custom page sizes
  • {page} / {totalPages} footer templates
  • Self-contained HTML/CSS output — nothing else to deploy
using TerraFluent.Html.Reporting.Model;

var report = ReportDocument.Create(PageSize.A4, PageOrientation.Portrait)
    .SetMargins(40, 40, 60, 60)
    .Header(h => h.AddText("Monthly Sales Report").AlignCenter().Bold())
    .Footer(f => f.AddPageNumber("Page {page} of {totalPages}"))
    .Content(c =>
    {
        c.AddHeading("Sales Summary", HeadingLevel.H1);
        c.AddParagraph("This report summarizes sales activity for the period.");
        c.AddTable(t =>
        {
            t.AddColumns("Product", "Qty", "Revenue");
            t.AddRow("Widget A", "120", "$2,400");
            t.AddRow("Widget B", "85", "$1,700");
        });
    })
    .Build();

report.RenderHtmlDocument("monthly-sales.html");
Tables

Merged cells that survive pagination

ColSpan and RowSpan handle merged summary cells and category groupings — and the layout engine treats a RowSpan group as atomic, so grouped rows never split across a page boundary.

  • Repeated table headers on every continued page
  • Configurable row splitting via RowSplitBehavior
  • Cell-count validation throws early, not at render time
table.AddColumns("Category", "Item", "Qty", "Total");

table.AddRow(new TableCell[]
{
    new TableCell("Electronics") { RowSpan = 3 },
    "Wireless Mouse", "2", "$39.98",
});
table.AddRow(new TableCell[] { "Mechanical Keyboard", "1", "$89.00" });
table.AddRow(new TableCell[] { "USB-C Dock", "1", "$64.50" });

table.AddRow(new TableCell[]
{
    new TableCell("Grand Total") { ColSpan = 3 },
    "$193.48",
});
Barcodes

Native Code 128 — no external library

Barcodes are generated in-library as PNG images: no barcode package, no web service. Available on content, header/footer, and row-column builders, with the same alignment/margin/padding modifiers as any image.

  • Invoice numbers in headers, tracking numbers on labels
  • Tunable module width, height, and quiet zone
  • Accepts printable ASCII values
// Defaults are fine for most cases:
c.AddBarcode("INV-1042");

// Or tune the geometry:
c.AddBarcode("20264471",
    moduleWidthPx: 2, heightPx: 40, quietZoneModules: 10);

// In an invoice header, right-aligned:
h.AddBarcode(invoiceNumber, moduleWidthPx: 2, heightPx: 40)
    .AlignRight();
Layout safety

Know before you ship: layout warnings

Content that can't fit on an empty page — an oversized image, an unsplittable block — raises a LayoutWarning instead of silently clipping. Inspect warnings after pagination and reject a bad report before a user sees it.

  • Line-level paragraph splitting and numbered-list continuation
  • Explicit page breaks where you want them
  • Warnings name the page and the element that didn't fit
using TerraFluent.Html.Reporting.Layout;

var layout = LayoutEngine.Paginate(report);

foreach (var warning in layout.Warnings)
{
    // "Page 1: A ReportImage required 300px but only ..."
    logger.LogWarning("{ReportWarning}", warning);
}
Scale

Stream large reports to disk

For reports too large to hold as one in-memory string, the async streaming API writes one page at a time — and won't block a thread-pool thread on the final flush inside an ASP.NET request handler.

  • RenderHtml() for strings, RenderHtmlDocument() for files
  • RenderHtmlDocumentAsync() with cancellation support
  • Pluggable ITextMeasurer via UseTextMeasurer(...) when page breaks must match a specific engine pixel-perfectly
await report.RenderHtmlDocumentAsync(
    Path.Combine(outputDir, "report.html"),
    cancellationToken: cancellationToken);
v1.1.1 · July 2026

What's new

  • Native Code 128 barcodesAddBarcode(...) on content, header/footer, and row-column builders; returns the same builder as AddImage.
  • Table cell ColSpan/RowSpan — merged header/summary cells and category groups, atomic during pagination.

Full changelog →

Documentation

Documented like a product

Thirteen guides from first report to custom renderers, plus a cookbook of runnable recipes.

FAQ

Frequently asked questions

How do I convert the HTML report output to PDF?

The output is print-perfect, self-contained HTML with fixed page geometry — print or save it as PDF from any browser, or feed it to any HTML-to-PDF converter you already trust. If you want PDF bytes server-side with no browser in the loop, use TerraFluent.Pdf.Reporting instead.

Does TerraFluent.Html.Reporting need a browser or PDF engine at runtime?

No. It is pure managed code that writes self-contained HTML/CSS — no headless browser, no PDF engine, no native binaries — so it deploys cleanly to Linux, Docker, and serverless.

Which .NET versions does TerraFluent.Html.Reporting support?

It targets netstandard2.0 and net10.0, so it runs on .NET Framework 4.6.1+, .NET Core 2.0+, and every modern .NET release on Windows, Linux, and macOS.

Can it generate barcodes?

Yes. Code 128 barcodes are generated in-library as crisp images — no external services or third-party barcode packages required.

Thirteen runnable samples included

Invoices, certificates, barcoded labels, row layouts, span tables — run dotnet run --project samples/TerraFluent.Html.Reporting.Sample or browse the rendered output online.

Need true PDF bytes server-side, with no browser in the loop? See TerraFluent.Pdf.Reporting.