Headings and table of contents
Mark a block as a heading and it becomes navigable in every format that has a notion of navigation:
var document = Document.Create(doc => doc .PageSize(PageSize.A4) .Margin(48f)
.Paragraph(p => p.Text("Contents", new TextStyle(FontSize: 16f, FontWeight: FontWeight.Bold))) .TableOfContents() .PageBreak()
.Paragraph(p => p.Text("Introduction")).Heading(1) .Paragraph(p => p.Text("Body text…")) .Paragraph(p => p.Text("Background")).Heading(2) .Paragraph(p => p.Text("More text…")));Heading(level) chains onto the block you just added - the same shape as
KeepTogether()/KeepWithNext(). Levels run from 1 to 6.
Titles
Section titled “Titles”A paragraph supplies its own title from its text. Anything else - a table, row, list, image, or line - has no text to borrow, so pass one:
doc.Table(t => …).Heading(2, "Quarterly results");doc.Image(logo).Heading(2, "Org chart");Omitting it there throws rather than producing a silently empty bookmark.
Headings do not change pagination
Section titled “Headings do not change pagination”Heading() only marks; it never moves content. To keep a heading with the section it introduces,
say so explicitly - the two compose in either order:
doc.Paragraph(p => p.Text("Chapter 3")).Heading(1).KeepWithNext() .Paragraph(p => p.Text("First paragraph of the chapter…"));Table of contents
Section titled “Table of contents”doc.TableOfContents(maxLevel: 3, leader: TocLeader.Dots, indentPerLevel: 14f);It lists every heading at or above maxLevel, in document order, and needs no separate list of
entries - the headings are the entries. Put a heading of your own above it if you want a
“Contents” title; the element renders only the entries.
In PDF each entry is one line: the title, a dot leader, and the real page number right-aligned at the content edge. Entries are clickable. A long title is truncated rather than wrapped, which is what lets the page numbers be filled in after pagination without shifting anything - the number column is a fixed width, so a three-digit page shortens the leader instead of moving the line.
Per format
Section titled “Per format”| Format | Headings | Table of contents |
|---|---|---|
| Bookmark outline in the reader’s sidebar, nested by level | Real page numbers, dot leaders | |
| DOCX | w:outlineLvl (Word’s navigation pane) + a bookmark per heading |
A native { TOC } field Word fills in |
| HTML | <h1>–<h6> with a stable id |
<nav> of in-page anchor links |
| XLSX | ignored | ignored |
A level skip attaches to the nearest open ancestor: 1 → 3 makes the level-3 heading a child of the
level-1 one rather than inventing an empty level 2. PDF and HTML apply the same rule, so the outline
and the nav list have the same shape.
What to expect per format
Section titled “What to expect per format”DOCX. Word computes the table of contents itself, because Papyra cannot know how Word will paginate. The document asks Word to build it on open; until it does, the field shows a short instruction. Right-click → Update Field refreshes it. One consequence: when a heading has an explicit title override, Word’s refreshed table shows the paragraph’s own text, since that is what Word collects. The override still governs PDF and HTML. A heading on a table or image needs a hidden marker paragraph, because an outline level is a paragraph property in Word.
HTML. No page numbers - a reflowable document has none, and the CSS counters that could supply
them when printing are not implemented by Chrome or Firefox. Ids are slugged from the title
(Chapter One → chapter-one) and deduplicated in document order, so two “Summary” headings become
summary and summary-2.
XLSX. A worksheet has no pages and no outline, so headings and the table of contents are both ignored - the same as watermarks and the keep flags.
Limitations
Section titled “Limitations”- Headings apply to top-level blocks only; a heading inside a table cell, list item, or header band is not expressible (the method exists only on the document and section builders).
- Page numbers appear in PDF only.
- No per-entry styling: entries inherit the document’s default text style.
- Levels are capped at 6, matching the HTML heading tags.
© 2026 Stefan Nikolei. Payments are processed by Paddle.com as merchant of record.