Overview
EggPdf.Fluent lets you describe a document with C# method calls. It builds the
same DOM the HTML parser would produce and hands it to the normal pipeline — cascade,
layout, pagination, paint, PDF writer — so there is no HTML string in the middle,
no escaping to get wrong, and the output is byte-for-byte the kind of PDF the HTML API makes.
Because it is the same engine, anything HTML/CSS can express, the fluent API can express
(see escape hatches).
It ships inside the main EggPdf package — there is nothing extra to install. Add
using EggPdf.Fluent; and call Document.Create(...).
dotnet add package EggPdfQuick start
using EggPdf.Fluent;
byte[] pdf = Document.Create(doc => doc
.Title("Invoice INV-142")
.Page(page => page
.Size(PageSize.A4)
.Margin(top: 70, right: 30, bottom: 50, left: 30)
.Header(h => h.Text("Acme Corp").Bold().FontSize(18))
.Footer(f => f.AlignCenter().PageNumberOfTotal()) // "Page 2 of 5"
.Watermark("DRAFT")
.Content(c =>
{
c.Heading(HeadingLevel.H1, "Invoice"); // also a PDF bookmark
c.Item().Row(row =>
{
row.RelativeItem().Text("Bill to: Jane Doe");
row.ConstantItem(Length.Mm(40)).AlignRight().Text("2026-09-24");
});
c.Item().Table(table =>
{
table.Header(h => { h.Cell().Text("Item").Bold(); h.Cell().Text("Qty").Bold(); });
foreach (var line in lines)
table.Row(r => { r.Cell().Text(line.Name); r.Cell().Text(line.Qty.ToString()); })
.AvoidBreakInside();
});
c.Item().PinBottom().Border(1, Colors.Gray).Padding(10).Text("Signature");
})))
.Render();
Document.Create(...) returns a DocumentBuilder with
Render(), RenderAsync(ct) and RenderToFileAsync(path, ct).
Building step by step
The nested form above is one style. You can equally create the document, keep it in a variable,
and fill in the header, footer and body in separate statements — or separate methods. Every
callback method has a parameterless twin that returns the thing to fill in
(Header(), Footer(), Content(), Row(),
Table(), Grid(...), BulletList(),
NumberedList(), Column()), and Document.New() /
AddPage() replace Document.Create / Page. Both styles
produce byte-identical PDFs.
var doc = Document.New().Title("Report");
var page = doc.AddPage().Size(PageSize.A4).Margin(30);
page.Header().Text("Acme").Bold();
page.Footer().AlignCenter().PageNumberOfTotal();
var body = page.Content();
body.Heading(HeadingLevel.H1, "Summary");
body.Item().Text("Quarterly results");
AddSalesTable(body); // ordinary helper method: one per report section
byte[] pdf = doc.Render(); // or RenderAsync(ct) / RenderToFileAsync(path, ct)
static void AddSalesTable(ColumnDescriptor content)
{
var table = content.Item().Table();
table.Header(h => { h.Cell().Text("Region").Bold(); h.Cell().Text("Sales").Bold(); });
table.Row(r => { r.Cell().Text("North"); r.Cell().Text("1,200"); });
}- Page settings can be changed at any point before rendering (
page.Size(...)after adding content is fine) — the@pagerule is written when the document is built. page.Content()can be called more than once; items append in call order.- Rendering builds and freezes the document. You can render it again (identical output), but any further change —
AddPage(),Text(...),Bold(),Title(...), … — throwsInvalidOperationExceptionrather than being silently lost. CallBuild()to freeze it explicitly. - The nested callbacks also accept normal statements and calls to helper methods that take a
Container/ColumnDescriptor, so you can mix the two styles freely.
Method chaining
Styling and configuration methods return the object they were called on, so they chain
(.Text("Hi").FontSize(20).Bold().Padding(8)). The methods that add a child
(Item, Cell, RelativeItem, ConstantItem,
Heading, table Header/Row) normally return that child, which
is what lets you style it. Each also has an overload taking a callback that returns the
parent instead, so siblings chain too and a whole document is one expression:
Document.Create(doc => doc
.Title("Chained")
.Page(p => p.Size(PageSize.A4).Margin(30).Content(c => c
.Item(i => i.Text("Intro").Bold())
.Heading(HeadingLevel.H2, "Section", h => h.FontColor(Colors.Navy))
.Item(i => i.Row(r => r
.Gap(5)
.RelativeItem(x => x.Text("Left"))
.ConstantItem(60, x => x.Text("Mid"))
.RelativeItem(2, x => x.Text("Wide"))))
.Item(i => i.Grid(2, g => g
.Item(x => x.Text("G1"))
.Item(2, x => x.Text("Spans both columns"))))
.Item(i => i.BulletList(l => l.Item(x => x.Text("One")).Item(x => x.Text("Two"))))
.Item(i => i.Table(t => t
.Header(h => h.Cell(x => x.Text("Item")).Cell(x => x.Text("Qty")), r => r.Background(Colors.LightGray))
.Row(r => r.Cell(x => x.Text("Widget")).Cell(x => x.Text("3")), r => r.AvoidBreakInside()))))))
.Render();
The table overloads take a second callback that styles the row box itself. All three styles —
chained, nested statements, and step by step — can be mixed freely and
produce identical PDFs. Pages chain through Page(...):
doc.Page(...).Page(...).
Structure
The builder is a tree of small descriptor types; each callback receives the one you need next:
| Type | What it configures |
|---|---|
DocumentDescriptor | Document-wide: title, author, language, CSS, fonts, PDF options, and Page(...) groups. |
PageDescriptor | One page group: size, margins, header, footer, watermark, Content(...). |
ColumnDescriptor | Stacked children: Item() and Heading(level, text). |
Container | A box. Everything you place returns a Container, so styling always applies to what you just placed. |
RowDescriptor / GridDescriptor / TableDescriptor / ListDescriptor | Children of a row (flex), grid, table or list. |
Typed values — no magic strings
A misspelled CSS keyword, color or unit is silently ignored by a CSS engine, which makes for PDFs that look wrong with no error anywhere. Every typed method therefore takes a typed value, and constructing an invalid one fails immediately.
| Type | Use | Validation |
|---|---|---|
Color / Colors | Colors.Red, Color.FromRgb(255, 0, 0), Color.FromRgba(0, 0, 0, 128), Color.FromHex("#f00") | FromHex accepts #rgb, #rgba, #rrggbb, #rrggbbaa only. There is deliberately no implicit conversion from string. |
Length | Length.Px/Pt/Mm/Cm/In/Em/Percent, Length.Auto. A bare number converts to pixels: Width(200). | NaN / infinity throw. |
| Keyword enums | OverflowMode, PositionMode, DisplayMode, FloatSide, FlexJustify, FlexAlign, TextCase, BorderLineStyle, WhiteSpaceMode, TextDirection, HeadingLevel | Exhaustive mapping to CSS; an undefined value throws. |
CssTransform | CssTransform.Rotate(10).Then(CssTransform.Scale(1.2f)); also Translate, SkewX, SkewY | Composes in order. |
GridTrack | GridTrack.Fr(2), GridTrack.Fixed(Length.Px(80)), GridTrack.Auto | Fr must be positive. |
Numeric ranges are checked too: Opacity (0–1), FontWeight (1–1000),
LineHeight (positive), grid column counts and spans (≥ 1). Plain string
parameters remain only where the value is genuinely free text: content, URLs and paths, ids and
class names, font family names, titles.
Content
Text and styling
c.Item()
.Text("Quarterly report")
.FontSize(20).Bold().FontColor(Colors.Navy)
.LetterSpacing(Length.Px(0.5f)).TextTransform(TextCase.Uppercase)
.Padding(8, 12).Background(Color.FromHex("#f1f5f9"))
.Border(1, Colors.LightGray, BorderLineStyle.Dashed).BorderRadius(6)
.BoxShadow(0, 2, 6, Color.FromRgba(0, 0, 0, 64));| Area | Methods |
|---|---|
| Typography | FontSize, FontFamily, Bold, Italic, FontWeight, FontColor, LineHeight (multiplier or Length), LetterSpacing, Underline, StrikeThrough, NoTextDecoration, TextTransform, WhiteSpace, AlignLeft/AlignCenter/AlignRight |
| Box model | Padding and Margin (1, 2 or 4 values), Width, Height, MinWidth, MaxWidth, MinHeight, MaxHeight |
| Decoration | Background, Border, BorderTop/Right/Bottom/Left, BorderRadius, BoxShadow, Opacity |
| Layout / effects | Overflow, Position, Display, Float, Transform |
| Attributes | Id, Class (repeatable), Direction |
Column and Row
A column is normal block flow (Item() per child). A row is a flex container: items
are RelativeItem(weight) (shares remaining space) or ConstantItem(width)
(fixed). The row itself is styled through RowDescriptor:
c.Item().Row(row =>
{
row.Gap(12).JustifyContent(FlexJustify.SpaceBetween).AlignItems(FlexAlign.Center).Wrap();
row.RelativeItem(2).Text("Wide");
row.RelativeItem(1).Text("Narrow");
row.ConstantItem(Length.Mm(30)).Text("Fixed");
});Grid
c.Item().Grid(new[] { GridTrack.Fr(1), GridTrack.Fr(2) }, g =>
{
g.Gap(10).AutoRows(Length.Px(40));
g.Item().Text("A");
g.Item().Text("B");
g.Item(columnSpan: 2).Text("Spans both columns");
});
c.Item().Grid(3, g => { /* three equal columns */ });Tables
table.Header(...) emits a real <thead>, which repeats at the top of
every continuation page when the table spans pages (see Tables).
Header and Row return the row so you can style it —
.AvoidBreakInside() keeps a row from splitting across a page break. Cells default to
4×8 px padding and a light 1 px border; restyle any cell through the returned
Container. Tables default to 100% width with collapsed borders.
Lists, images, links, headings
c.Item().BulletList(l => { l.Item().Text("One"); l.Item().Text("Two"); });
c.Item().NumberedList(l => l.Item().Text("First"));
c.Item().Image("logo.png", widthPx: 80, heightPx: 40); // path, URL or data: URI
c.Item().Hyperlink("https://example.com", "Visit us");
c.Heading(HeadingLevel.H2, "Section"); // real <h2>: bookmark + PDF/UA heading
Relative image paths resolve against DocumentDescriptor.BasePath(...). Headings must be
created with Heading(...) (not a styled Item()) — bookmarks and the
accessibility structure tree key off the real h1–h6 tags.
Internal links
Give a box an id and link to it. The link is a real PDF destination (page + position), so it jumps forward or backward to any page:
c.Item().Hyperlink("#terms", "See the terms");
// ...
c.Item().Id("terms").Text("Terms and conditions");<a href="#terms"> +
<div id="terms">). If the id doesn't exist (or its element is
display: none) the link is dropped rather than written as a dead annotation. When
an id appears twice, the first one wins, as in a browser. As in a browser, href="#" and
href="#top" jump to the top of the document when no element has that id, and a
visibility: hidden element is still a valid target. An element that repeats on every
page (a position: fixed header or footer, e.g. PageDescriptor.Header) has a
single destination: its first occurrence, on page 1.
Pages, headers, footers
page.Size(PageSize.Letter.Landscape())
.Margin(top: 60, right: 20, bottom: 60, left: 20) // reserve room for the header/footer
.Header(h => h.Text("Confidential").FontColor(Colors.Gray))
.Footer(f => f.AlignRight().PageNumberOfTotal(prefix: "Page ", separator: " / "))
.Watermark("DRAFT", fontSize: Length.Px(120), rotationDegrees: -35, opacity: 0.1f, color: Colors.Red)- Sizes:
PageSize.A3/A4/A5/Letter/Legal,.Landscape(), ornew PageSize(widthMm, heightMm). - Header / footer repeat on every physical page of the group (
position: fixed). They don't push content down — leave room with the page margins. - Page numbers:
CurrentPageNumber(),TotalPages(),PageNumberOfTotal(). CSS allows a single generated::afterper element, so use one of these perContainer— a second call on the same container throws instead of silently replacing the first. Use separate containers (e.g. row items) for separate pieces. - Watermark is composed from
position: fixed,transformandopacity— there is no dedicated watermark feature in the CSS engine either. PinBottom()pins a box (e.g. a signature block) to the bottom of whichever page the preceding content ends on.
Multiple page groups (mixed sizes)
Content that overflows a page flows onto the next automatically. Call Page(...) more
than once to change size or orientation partway through — the first group is the base
@page rule and each later group gets its own named page (CSS Paged Media named pages):
Document.Create(doc => doc
.Page(p => p.Size(PageSize.A4).Content(c => c.Item().Text("Report body")))
.Page(p => p.Size(PageSize.A4.Landscape()).Content(c => c.Item().Text("Wide appendix table"))));Document-level options
Document.Create(doc => doc
.Title("Annual report").Author("Finance team").Language("en")
.BasePath(@"C:\assets") // resolves relative images/fonts/CSS
.FontFace("Brand Sans", "fonts/brand.ttf", weight: 700)
.Css(".total { font-weight: 700 } @media print { .noprint { display: none } }")
.Conformance(PdfAConformance.PdfA2b) // PDF/A archival
.Tagged() // PDF/UA accessible
.Page(...));| Method | Effect |
|---|---|
Title, Author | PDF document info. |
Language | lang on the root; used by tagged output. |
Css | Raw stylesheet in <head>; target boxes with Class(...)/Id(...). |
FontFace | @font-face webfont (URL, file path or data: URI); see Fonts. |
BasePath | Base directory for relative resources. |
Encrypt | RC4 permission/password protection (PdfEncryption). |
Conformance, Invoice | PDF/A levels; Factur-X e-invoice (needs PDF/A-3b/3u). See Compliance. |
Tagged | PDF/UA-1 (or UA-2) tagged output. |
Escape hatches
When a feature has no typed method yet, four explicitly unchecked hatches guarantee you are never
blocked. They are named Raw* on purpose, so unchecked strings are visible at every call site:
c.Item().RawStyle("column-count", "2"); // any CSS declaration
c.Item().RawAttribute("data-section", "intro"); // any HTML attribute
c.Item().Raw("<dl><dt>Term</dt><dd>Definition</dd></dl>"); // any HTML markup, spliced into the tree
doc.Css("@page :first { @top-center { content: 'Cover' } }"); // any stylesheetRaw* call as a sign a typed method is missing.
Validation and errors
- Invalid typed values throw at the call site:
Color.FromHex("red")andLength.Px(float.NaN)throwArgumentException/ArgumentOutOfRangeException. - Out-of-range numbers (
Opacity(1.5f),FontWeight(0),Grid(0, ...),Heading((HeadingLevel)9, ...)) throwArgumentOutOfRangeException. - A second page-number/generated-content call on one container throws
InvalidOperationException. - Rendering problems behave exactly as in the HTML API (missing images and fonts degrade gracefully; PDF/A rule violations throw).
How it works
Fluent calls accumulate typed style declarations per element. When Document.Create
returns, they are serialized once into style/class attributes on an
in-memory HtmlDocument, which is passed to
HtmlToPdf.RenderDocument(...) — the same entry the HTML string API reaches after
parsing. See Architecture. Because nothing is generated as text,
content is never HTML-escaped or re-parsed, and a fluent document and the equivalent HTML render identically.
API reference
Every public type and member of EggPdf.Fluent, with its purpose. This section is
generated from the code and its XML doc comments
(dotnet run --project tools/EggPdf.DocGen), so it always matches the API; the same
summaries appear as IntelliSense in your editor.
A callback overload takes an Action and returns the parent (for chaining); the
parameterless overload returns the child (to style it or fill it in with separate statements).
Types: Document, DocumentBuilder, DocumentDescriptor, PageDescriptor, ColumnDescriptor, Container, RowDescriptor, GridDescriptor, ListDescriptor, TableDescriptor, TableRowDescriptor, Color, Colors, Length, CssTransform, GridTrack, PageSize, and the keyword enums.
Document (static)
Entry point for defining PDF content in C# instead of HTML. It builds a DOM directly from the fluent calls and hands it to HtmlToPdf unchanged -- same cascade/layout/paint/ PDF-write pipeline as the HTML API, just without ever going through an HTML string. Two styles, same result: declarative (Create, one callback) or step by step (New).
| Member | Purpose |
|---|---|
static DocumentBuilder Create(Action<DocumentDescriptor> build) | Builds a document from build's fluent calls, ready to render. |
static DocumentDescriptor New() | Starts an empty document to fill in step by step -- keep the returned descriptor, add pages, headers, footers and content in separate statements (or separate methods), then call Render: |
DocumentBuilder
The finished document, ready to render. Returned by Create.
| Member | Purpose |
|---|---|
byte[] Render() | Renders the document to PDF bytes. May be called repeatedly; the output is identical each time. |
Task<byte[]> RenderAsync(CancellationToken ct = default) | Renders the document to PDF bytes asynchronously. |
Task RenderToFileAsync(string filePath, CancellationToken ct = default) | Renders the document and writes the PDF to filePath. |
DocumentDescriptor
Root of the fluent builder: a document is one or more page groups, plus document-wide PDF options. Build it either declaratively inside Create's callback, or step by step: var doc = Document.New(); var page = doc.AddPage(); page.Header().Text("..."); ... doc.Render(); Both produce the same document. Once built or rendered a document is frozen -- further changes throw.
| Member | Purpose |
|---|---|
PageDescriptor AddPage() | Adds a page group and returns it to configure imperatively (size, margins, header, footer, content) at any later point before the document is built. The first group is the document's base (unnamed) page size; every group after that gets its own named @page rule and a matching page: <name> on its content root, so later groups can use a different size/orientation (e.g. a landscape appendix) -- the same CSS Paged Media named-page mechanism HTML documents use for mixed page sizes. |
DocumentDescriptor Page(Action<PageDescriptor> build) | Adds a page group configured inside build (see AddPage). |
DocumentBuilder Build() | Finishes the document: serializes every accumulated style and page rule, and freezes it. Called automatically by Render, RenderAsync and RenderToFileAsync; calling it again returns the same result. After this, changing the document throws. |
byte[] Render() | Builds the document (see Build) and renders it to PDF bytes. |
Task<byte[]> RenderAsync(CancellationToken ct = default) | Builds the document and renders it to PDF bytes asynchronously. |
Task RenderToFileAsync(string filePath, CancellationToken ct = default) | Builds the document and renders it to a PDF file. |
DocumentDescriptor Title(string title) | The PDF's title metadata (HTML <title>). |
DocumentDescriptor Author(string author) | The PDF's author metadata (HTML <meta name="author">). |
DocumentDescriptor Language(string lang) | The document language (lang on <html>), e.g. "en"; used by tagged (PDF/UA) output. |
DocumentDescriptor Css(string css) | Adds a raw stylesheet to the document's <head> -- the head-level counterpart to Style/Raw: selectors, @media print, @import, anything. Pair with Attribute to give elements classes/ids to target. |
DocumentDescriptor FontFace(string family, string src, int weight = 400, bool italic = false) | Declares an @font-face webfont; src is a URL, file path or data: URI. |
DocumentDescriptor BasePath(string basePath) | Base directory for resolving relative resource paths (images, stylesheets, fonts). |
DocumentDescriptor Encrypt(PdfEncryption encryption) | Encrypts the PDF (RC4 view-only protection / permission flags). |
DocumentDescriptor Conformance(PdfAConformance conformance) | Renders a PDF/A-conformant PDF (ICC output intent, XMP conformance metadata, forced font embedding). |
DocumentDescriptor Invoice(FacturXInvoice invoice) | Attaches a Factur-X/ZUGFeRD e-invoice XML. Conformance must be set to PdfA3b or PdfA3u first. |
DocumentDescriptor Tagged(PdfUaVersion uaVersion = PdfUaVersion.Ua1) | Renders a PDF/UA tagged (accessible) PDF: structure tree, headings, landmarks, alt text, tagged links. |
PageDescriptor
Configures one page group's size, margins, running header/footer/watermark and content. Size/margin become an injected @page rule (named, for every group after the first -- see Page); content becomes the group's stacked (Column) body, the same way HTML's <body> is.
| Member | Purpose |
|---|---|
PageDescriptor Size(PageSize size) | The physical page size and orientation. |
PageDescriptor Margin(Length all) | Same margin on all four sides. |
PageDescriptor Margin(Length top, Length right, Length bottom, Length left) | Per-side margins, in CSS shorthand order (top, right, bottom, left). |
PageDescriptor Header(Action<Container> build) | A running header repeated on every physical page of this group (CSS position: fixed pinned to the page's top edge). Reserve room for it with Margin. |
Container Header() | The running header (see Header) as a Container to fill in with separate statements. |
PageDescriptor Footer(Action<Container> build) | A running footer repeated on every physical page of this group, pinned to the page's bottom edge. |
Container Footer() | The running footer (see Footer) as a Container to fill in with separate statements. |
PageDescriptor Watermark(string text, Length? fontSize = null, float rotationDegrees = -30f, float opacity = 0.12f, Color? color = null) | A rotated, translucent text overlay ("DRAFT", "CONFIDENTIAL", ...) repeated centered on every physical page of this group. Composed from position:fixed/transform/opacity, the same primitives an HTML author would reach for -- there's no dedicated watermark keyword in the CSS engine either. color defaults to mid gray. |
PageDescriptor Content(Action<ColumnDescriptor> build) | Builds the group's content, stacked top to bottom like a <body>. |
ColumnDescriptor Content() | The group's content column, to add items to with separate statements. May be used more than once (items append in call order) -- e.g. one method per section of the report. |
ColumnDescriptor
Builds the stacked (top-to-bottom) children of a Column.
| Member | Purpose |
|---|---|
Container Item() | Appends a new block-level item to the column and returns it for styling/content. |
ColumnDescriptor Item(Action<Container> build) | Appends an item configured inside build and returns the column, so items chain: col.Item(i => ...).Item(i => ...). |
ColumnDescriptor Heading(HeadingLevel level, string text, Action<Container> style) | Appends a heading styled inside style and returns the column, so it chains with Item. |
Container Heading(HeadingLevel level, string text) | Appends a real <h1>-<h6> (not a styled div): headings are what the PDF/UA structure tree and auto-generated PDF bookmarks key off, so this is the only way to get a document's table of contents/outline from the fluent API. |
Container
A single box in the document tree (a <div> under the hood). Every content-producing fluent call (Column, Row, page content, row/column items) hands back a Container, so text and styling always apply to "whatever was placed last". Styling takes typed values (Color, Length, keyword enums); the Raw* methods are the explicit, unchecked escape hatches.
| Member | Purpose |
|---|---|
Container Text(string text) | Appends text to this container (each call adds another text node, so Text("a").Text("b") renders "ab"). |
Container Column(Action<ColumnDescriptor> build) | Stacks children top to bottom (normal block flow -- CSS's default). |
ColumnDescriptor Column() | The children column of this container, to add items to with separate statements. |
Container Row(Action<RowDescriptor> build) | Lays out children left to right (display: flex). |
RowDescriptor Row() | Starts a row (flex container) appended here and returns it to fill in with separate statements. |
Container Table(Action<TableDescriptor> build) | Builds a <table> -- <thead> rows added via Header repeat on every continuation page for tables that span more than one page, the same as a hand-written <thead> does. |
TableDescriptor Table() | Starts a table appended here and returns it to fill in with separate statements (see Table). |
Container BulletList(Action<ListDescriptor> build) | Appends a bulleted list (<ul>). |
ListDescriptor BulletList() | Starts a bulleted list and returns it to add items to with separate statements. |
Container NumberedList(Action<ListDescriptor> build) | Appends a numbered list (<ol>). |
ListDescriptor NumberedList() | Starts a numbered list and returns it to add items to with separate statements. |
Container Grid(GridTrack[] columns, Action<GridDescriptor> build) | Lays out children in a CSS grid with the given column tracks. |
GridDescriptor Grid(GridTrack[] columns) | Starts a grid with the given column tracks and returns it to add cells to with separate statements. |
Container Grid(int columnCount, Action<GridDescriptor> build) | Lays out children in a CSS grid of columnCount equal columns. |
GridDescriptor Grid(int columnCount) | Starts a grid of columnCount equal columns and returns it to add cells to with separate statements. |
Container Image(string src, float? widthPx = null, float? heightPx = null) | Appends an <img>. Width/height (in px) are HTML attributes, matching plain <img width height> sizing. |
Container Hyperlink(string url, string text) | Appends a clickable <a href> link. |
Container Id(string id) | Sets this box's id, the target of internal links (Hyperlink("#id", ...)) and of Css selectors. |
Container Class(string className) | Adds a CSS class (repeatable; classes accumulate) for Css selectors to target. |
Container Direction(TextDirection direction) | Text direction of this box (dir). |
Container PinBottom() | Pins this box to the bottom of whichever physical page its surrounding dynamic content ends on (e.g. a signature block). |
Container AvoidBreakInside() | Keeps this box from being split across a page break (break-inside: avoid) -- e.g. a table row that must not straddle two pages. |
Container CurrentPageNumber() | Renders as the current physical page number, e.g. inside a Footer. Generated content (CSS counter()) can only be expressed via a real ::after rule, not an inline style="" attribute, so this registers one under a fresh class name. |
Container TotalPages() | Renders as the document's total physical page count. |
Container PageNumberOfTotal(string prefix = "Page ", string separator = " of ", string suffix = "") | Renders as e.g. "Page 3 of 12". |
Container FontSize(Length size) | Font size (a bare number is px). |
Container FontFamily(string family) | Font family name or comma-separated fallback list, e.g. "Inter, Arial" (free text -- a family, not a CSS keyword). |
Container Bold() | Bold text (font-weight: bold). |
Container Italic() | Italic (slanted) text. |
Container FontWeight(int weight) | Numeric weight, 1-1000 (400 = normal, 700 = bold). |
Container FontColor(Color color) | Text color. |
Container LineHeight(float multiplier) | Unitless line-height multiplier (1.4 = 140% of the font size). |
Container LineHeight(Length height) | Absolute line-height. |
Container LetterSpacing(Length spacing) | Extra space between characters. |
Container Underline() | Underlined text. |
Container StrikeThrough() | Struck-through text. |
Container NoTextDecoration() | Removes text decoration (e.g. the underline links get by default). |
Container TextTransform(TextCase textCase) | Upper/lower/capitalize case transformation of the rendered text. |
Container WhiteSpace(WhiteSpaceMode mode) | How white space and line breaks in the text are handled. |
Container AlignLeft() | Aligns text to the left edge. |
Container AlignCenter() | Centers text. |
Container AlignRight() | Aligns text to the right edge. |
Container Padding(Length all) | Inner spacing on all four sides. |
Container Padding(Length vertical, Length horizontal) | Inner spacing: vertical (top and bottom), then horizontal (left and right). |
Container Padding(Length top, Length right, Length bottom, Length left) | Inner spacing per side, in CSS order: top, right, bottom, left. |
Container Margin(Length all) | Outer spacing on all four sides. |
Container Margin(Length vertical, Length horizontal) | Outer spacing: vertical (top and bottom), then horizontal (left and right). |
Container Margin(Length top, Length right, Length bottom, Length left) | Outer spacing per side, in CSS order: top, right, bottom, left. |
Container Width(Length width) | Box width. |
Container Height(Length height) | Box height. |
Container MinWidth(Length width) | Minimum box width. |
Container MaxWidth(Length width) | Maximum box width. |
Container MinHeight(Length height) | Minimum box height. |
Container MaxHeight(Length height) | Maximum box height. |
Container Background(Color color) | Background fill color. |
Container Border(Length width, Color color, BorderLineStyle style = BorderLineStyle.Solid) | Border on all four sides. |
Container BorderTop(Length width, Color color, BorderLineStyle style = BorderLineStyle.Solid) | Top border only. |
Container BorderRight(Length width, Color color, BorderLineStyle style = BorderLineStyle.Solid) | Right border only. |
Container BorderBottom(Length width, Color color, BorderLineStyle style = BorderLineStyle.Solid) | Bottom border only. |
Container BorderLeft(Length width, Color color, BorderLineStyle style = BorderLineStyle.Solid) | Left border only. |
Container BorderRadius(Length radius) | Rounded corners. |
Container BoxShadow(Length offsetX, Length offsetY, Length blur, Color color) | Drop shadow: horizontal offset, vertical offset, blur radius, color. |
Container Opacity(float value) | 0 (transparent) to 1 (opaque). |
Container Overflow(OverflowMode mode) | What happens to content that doesn't fit the box (Hidden clips it). |
Container Position(PositionMode mode) | Positioning scheme (position). |
Container Display(DisplayMode mode) | Display type (display). |
Container Float(FloatSide side) | Floats the box left or right so following inline content wraps around it. |
Container Transform(CssTransform transform) | Applies a 2D transform (rotate, scale, translate, skew), e.g. CssTransform.Rotate(10). |
Container RawStyle(string property, string value) | Unchecked escape hatch: sets any CSS declaration by name and value. Nothing validates either string, so a typo is silently ignored by the CSS engine -- prefer the typed methods above, and use this only for a property that has none yet. |
Container RawAttribute(string name, string value) | Unchecked escape hatch: sets any HTML attribute by name. class is added to the classes the builder manages (so it combines with Class and page-number classes instead of being overwritten); a style attribute is rejected -- use RawStyle, which merges with the typed styles. For any other name the first value set wins. |
Container Raw(string html) | Unchecked escape hatch: parses html as an HTML fragment and appends its nodes as children -- anything expressible in HTML is expressible here, even before a typed wrapper exists for it. |
RowDescriptor
Builds the side-by-side (flex) children of a Row.
| Member | Purpose |
|---|---|
RowDescriptor Gap(Length gap) | Space between items along the row (gap). It applies to the row itself, so it can be set before or after adding items. |
RowDescriptor JustifyContent(FlexJustify justify) | How items distribute along the row (justify-content). |
RowDescriptor AlignItems(FlexAlign align) | How items align across the row's height (align-items). |
RowDescriptor Wrap() | Lets items wrap onto additional lines instead of shrinking to fit one row (flex-wrap: wrap). |
Container RelativeItem(float weight = 1f) | Appends an item that shares the row's remaining space by weight (flex-grow). |
RowDescriptor RelativeItem(Action<Container> build) | Appends a flexible item configured inside build and returns the row, so items chain. |
RowDescriptor RelativeItem(float weight, Action<Container> build) | Appends a flexible item of the given weight configured inside build and returns the row. |
RowDescriptor ConstantItem(Length width, Action<Container> build) | Appends a fixed-width item configured inside build and returns the row, so items chain. |
Container ConstantItem(Length width) | Appends an item with a fixed width that does not grow or shrink. |
GridDescriptor
Builds the cells of a CSS grid container (Grid).
| Member | Purpose |
|---|---|
GridDescriptor Gap(Length gap) | Space between rows and columns (gap). |
GridDescriptor AutoRows(Length height) | Height of implicitly created rows (grid-auto-rows). |
GridDescriptor Item(Action<Container> build) | Appends a single-column cell configured inside build and returns the grid, so cells chain. |
GridDescriptor Item(int columnSpan, Action<Container> build) | Appends a cell spanning columnSpan columns configured inside build and returns the grid. |
Container Item(int columnSpan = 1) | Appends a cell spanning columnSpan columns and returns it for content/styling. |
ListDescriptor
Builds the <li> items of a bullet (<ul>) or numbered (<ol>) list.
| Member | Purpose |
|---|---|
ListDescriptor Item(Action<Container> build) | Appends a list item configured inside build and returns the list, so items chain. |
Container Item() | Appends a list item and returns it for content/styling (it may itself hold nested lists, tables, etc.). |
TableDescriptor
Builds a table's <thead> and <tbody> rows.
| Member | Purpose |
|---|---|
Container Header(Action<TableRowDescriptor> build) | Adds a header row inside <thead>, which repeats on every continuation page for tables spanning more than one page. Returns the row for styling (e.g. a header background). |
TableDescriptor Header(Action<TableRowDescriptor> cells, Action<Container> rowStyle) | Adds a header row whose cells are built by cells and whose row box is styled by rowStyle; returns the table, so rows chain. |
TableDescriptor Row(Action<TableRowDescriptor> cells, Action<Container> rowStyle) | Adds a body row whose cells are built by cells and whose row box is styled by rowStyle; returns the table, so rows chain. |
Container Row(Action<TableRowDescriptor> build) | Adds a body row inside <tbody>. Returns the row for styling (e.g. striping, AvoidBreakInside). |
TableRowDescriptor
Builds one table row's cells.
| Member | Purpose |
|---|---|
TableRowDescriptor Cell(Action<Container> build) | Appends a cell configured inside build and returns the row, so cells chain. |
Container Cell() | Appends a cell (<th> in a header row, <td> otherwise) and returns it for content/styling. |
Color (struct)
A validated color. There is deliberately no implicit conversion from string: a typo like "rde" must fail at the call site (FromHex throws) rather than be silently ignored by the CSS engine. default(Color) is fully transparent.
| Member | Purpose |
|---|---|
static Color FromRgb(byte r, byte g, byte b) | An opaque color from red, green and blue components (0-255). |
static Color FromRgba(byte r, byte g, byte b, byte a) | RGB plus alpha (0 = transparent, 255 = opaque). |
static Color FromHex(string hex) | Parses "#rgb", "#rgba", "#rrggbb" or "#rrggbbaa"; anything else throws. |
Colors (static)
Common named colors, as Color values.
Named colors: Transparent, Black, White, Red, Green, Blue, Yellow, Orange, Purple, Pink, Brown, Navy, Teal, Gray, LightGray, DarkGray.
Length (struct)
A CSS length with its unit. A bare number converts implicitly to pixels, so Width(200) still works; use Mm, Percent etc. for anything else. default(Length) is 0px.
| Member | Purpose |
|---|---|
static Length Px(float value) | A length in CSS pixels. |
static Length Pt(float value) | A length in points (1/72 inch). |
static Length Mm(float value) | A length in millimeters. |
static Length Cm(float value) | A length in centimeters. |
static Length In(float value) | A length in inches. |
static Length Em(float value) | A length relative to the element's font size (1 em = one font size). |
static Length Percent(float value) | A length as a percentage of the containing box. |
implicit operator Length(float px) | A bare number converts to pixels, so Width(200) means 200 px. |
static Length Zero { get; } | A zero length (0 px). |
static Length Auto { get; } | The CSS keyword auto (the browser/engine picks the size). |
CssTransform (struct)
A 2D transform, composable with Then: CssTransform.Rotate(10).Then(CssTransform.Scale(1.2f)).
| Member | Purpose |
|---|---|
static CssTransform Rotate(float degrees) | Rotates clockwise by degrees around the box's center. |
static CssTransform Scale(float factor) | Scales uniformly by factor (1 = unchanged, 2 = double size). |
static CssTransform Scale(float x, float y) | Scales by separate horizontal and vertical factors. |
static CssTransform Translate(Length x, Length y) | Moves the box by a horizontal and a vertical offset. |
static CssTransform SkewX(float degrees) | Skews (slants) horizontally by degrees. |
static CssTransform SkewY(float degrees) | Skews (slants) vertically by degrees. |
CssTransform Then(CssTransform next) | Applies next after this transform. |
GridTrack (struct)
One column of a Grid.
| Member | Purpose |
|---|---|
static GridTrack Fr(float share) | A flexible share of the remaining space (Nfr). |
static GridTrack Fixed(Length size) | A fixed-size column. |
static GridTrack Auto { get; } | Sized to its content. |
PageSize (struct)
A page's physical dimensions in millimeters, matching CSS @page { size: ... }.
| Member | Purpose |
|---|---|
static readonly PageSize A3 | A3 portrait (297 x 420 mm). |
static readonly PageSize A4 | A4 portrait (210 x 297 mm) -- the default. |
static readonly PageSize A5 | A5 portrait (148 x 210 mm). |
static readonly PageSize Letter | US Letter portrait (8.5 x 11 in). |
static readonly PageSize Legal | US Legal portrait (8.5 x 14 in). |
PageSize(float widthMm, float heightMm) | A custom page size in millimeters. |
PageSize Landscape() | Same physical page, rotated: width and height swapped. |
float WidthMm { get; } | Page width in millimeters. |
float HeightMm { get; } | Page height in millimeters. |
Keyword enums
| Enum | Purpose | Values |
|---|---|---|
BorderLineStyle | Border line style. | None, Solid, Dashed, Dotted, Double, Groove, Ridge, Inset, Outset |
DisplayMode | display. | None, Block, Inline, InlineBlock, Flex, Grid |
FlexAlign | Flex align-items: alignment across the row's height. | Stretch, Start, Center, End, Baseline |
FlexJustify | Flex justify-content: distribution along the row. | Start, Center, End, SpaceBetween, SpaceAround, SpaceEvenly |
FloatSide | float. | None, Left, Right |
HeadingLevel | Heading level; the value is the N of <hN>. | H1, H2, H3, H4, H5, H6 |
OverflowMode | overflow: what happens to content that doesn't fit the box. | Visible, Hidden, Clip, Scroll, Auto |
PositionMode | position. | Static, Relative, Absolute, Fixed, Sticky |
TextCase | text-transform. | None, Uppercase, Lowercase, Capitalize |
TextDirection | Text direction (dir). | Ltr, Rtl |
WhiteSpaceMode | white-space. | Normal, NoWrap, Pre, PreWrap, PreLine |