Lines, page breaks, and pagination
Horizontal lines
Section titled “Horizontal lines”A horizontal rule across the content width:
doc.Line(); // default thickness and colordoc.Line(thickness: 2f, color: Colors.Teal.Medium);Lines are a quick way to separate a letterhead from the body, or totals from the line items.
Partial-width lines
Section titled “Partial-width lines”width limits the line’s length (in points) and alignment positions it within the content width - the classic use is the short rule above an invoice’s grand total:
doc.Line(2f, width: 220f, alignment: TextAlignment.Right);doc.Line(1f, width: 100f, alignment: TextAlignment.Center);width must be positive (it is clamped to the content width), and JUSTIFY is rejected. Per-format behavior:
- PDF draws the line at its exact position and length.
- DOCX renders the line as a paragraph bottom border between matching left/right indents - native Word behavior, exact position and length.
- XLSX approximates: the line becomes a bottom border on the grid columns its box overlaps, so its edges snap to the sheet’s column boundaries.
Dashed and dotted lines
Section titled “Dashed and dotted lines”style switches the stroke pattern - LineStyle.Solid (default), DASHED, or DOTTED:
doc.Line(1f, style: LineStyle.Dashed);doc.Line(2f, Colors.Blue.Medium, width: 200f, style: LineStyle.Dotted);PDF strokes the dash pattern directly (3× thickness on / 2× off for dashed, thickness-sized square dots for dotted); DOCX uses the native dashed/dotted paragraph border values; HTML emits the CSS border-style keyword. XLSX maps the line’s bottom-border approximation onto Excel’s dashed/dotted border styles - the thickness-based weight is dropped for dotted, which Excel only offers in one weight.
Page breaks
Section titled “Page breaks”Force the following content onto a new page:
doc.Paragraph(p => p.Text("End of summary.")) .PageBreak() .Paragraph(p => p.Text("Appendix A"));Page breaks apply to paginated output - PDF and DOCX. XLSX ignores them (a spreadsheet has no pages).
Automatic pagination - content flowing onto new pages when it runs out of space - happens regardless; PageBreak is for the places where you want the break, not where the space forces one.
Keeping content together
Section titled “Keeping content together”Two chaining methods control where the automatic breaks may fall. Both apply to the most recently added top-level block (paragraph, table, row, list, image, or line):
doc.Paragraph(h => h.Text("Positions")) .KeepWithNext() // the heading stays with the table's first row .Table(t => ...);
doc.Table(t => ...) .KeepTogether(); // the whole table moves to the next page instead of splittingKeepWithNext()binds the block to the start of the following block. Chains are transitive - three consecutiveKeepWithNext()blocks move as one unit. The flag is inert on the last element and before an explicitPageBreak()(the break wins).KeepTogether()prevents the block from being split across pages. Paragraphs, images, rows, and lines are never split anyway; for tables and lists the flag suppresses the row/item splitting when the block fits on one page.
Content is never lost to these rules: a block or chain taller than one full page degrades gracefully - the chain places its members individually (still keeping the last pair together when that pair fits a page), and an oversized keep-together table or list falls back to normal row/item splitting.
Per-format behavior:
- PDF applies the rules exactly during its pagination pass.
- DOCX emits the native properties (
w:keepNext,w:keepLines,w:cantSplit) and lets Word paginate. Word has no whole-table keep, so a table’sKeepTogether()is approximated ascantSplitper row plus akeepNextchain through its rows.KeepWithNext()on a multi-paragraph block setskeepNexton all of its paragraphs, which also binds the block internally - consistent with the PDF behavior, where such a block moves as one unit. - XLSX has no pages and ignores both flags.
© 2026 Stefan Nikolei. Payments are processed by Paddle.com as merchant of record.