Appearance
Table of Contents
Press can automatically generate a table of contents by collecting elements marked as outline entries, then rendering them on a page marked as deferred.
Creating Outline Entries
Add the outline attribute to any element to register it in a named collection:
xml
<h1 outline="sections">Introduction</h1>This adds the element to a collection called "sections". You can create multiple collections for different purposes.
Outline Levels
Use the level attribute for hierarchical outlines:
xml
<h1 outline="sections" level="1">Data Sources</h1>
<h2 outline="sections" level="2">Satellite Data</h2>
<h2 outline="sections" level="2">Ground Stations</h2>
<h1 outline="sections" level="1">Analysis</h1>level and outline can also be set in <styles>:
xml
<styles>
<h1>
<level>1</level>
<outline>custom-headings</outline>
</h1>
</styles>Default Headings Outline
When you use the default <h1> through <h6> tags, they are automatically added to a default collection called "headings" with appropriate levels. You don't need to add outline manually for standard headings in flows.
Deferred Pages
A table of contents needs to know the page number of every entry. Papermill achieves this through deferred pages and flows.
xml
<page deferred="true">
<h1>Contents</h1>
<!-- This content is rendered after all other pages -->
</page>Tables of Contents Page
Here's a page definition called <toc> which renders a custom contents page:
xml
<pages>
<toc deferred="true" flow="contents" repeat="true">
<flow deferred="true" name="contents">
<h1>Contents</h1>
<table>
<repeat outline="sections" item="entry">
<tr>
<td width="40pt">{{ entry.page-number }}</td>
<td width="fill">{{ entry.text-content }}</td>
</tr>
</repeat>
</table>
</flow>
</toc>
</pages>Include this in <documents> at the place where you want the table of contents to render:
xml
<documents>
<toc />
</documents>Outline Entry Properties
When iterating over an outline collection, each entry has these properties:
| Property | Description |
|---|---|
page-number | The page number where the entry appears |
text-content | The text content of the element |
index | The position in the collection (1-based) |
level | The hierarchy level (if set) |
Building a Contents Page
Here's a complete example of a report with an auto-generated table of contents:
xml
<<press>
<document format="A4" page-margin="2cm">
<coverpage />
<toc />
<repeat flow="body">
<body-page />
</repeat>
</document>
<pages>
<coverpage>
<frame height="fill" v-align="center">
<h1 font-size="36pt">{{ data.title }}</h1>
<p font-size="14pt" font-color="#6b7280">{{ data.subtitle }}</p>
</frame>
</coverpage>
<toc deferred="true" flow="contents" repeat="true">
<flow deferred="true" name="contents">
<frame font-style="bold" font-size="18pt" margin-bottom="20pt">
Contents
</frame>
<table>
<repeat outline="sections" item="entry">
<show-if condition="entry.page-number">
<tr>
<td font-size="14pt">{{ entry.page-number }}</td>
<td width="fill">{{ entry.text-content }}</td>
</tr>
</show-if>
</repeat>
</table>
</flow>
</toc>
<body-page>
<frame padding-bottom="40pt" height="fill">
<flow name="body" />
</frame>
<frame text-align="center" font-size="9pt">
Page <page-number />
</frame>
</body-page>
</pages>
<flows>
<body type="markdown">
<h1 outline="sections">Executive Summary</h1>
The organisation achieved record growth in 2025, driven by
expansion into three new markets and a 40% increase in
recurring revenue.
<frame-break />
<h1 outline="sections">Financial Overview</h1>
Total revenue reached £12.4M, a 28% increase year-on-year.
Operating margins improved to 18%, up from 14% in the
previous fiscal year.
<frame-break />
<h1 outline="sections">Strategic Outlook</h1>
The board has approved investment in two new product lines
for 2026, targeting the healthcare and education sectors.
</body>
</flows>
<styles>
<table>
<child name="td">
<border-weight>0</border-weight>
<border-weight-bottom>0.5pt</border-weight-bottom>
<border-color>#e5e7eb</border-color>
<padding-top>6pt</padding-top>
<padding-bottom>6pt</padding-bottom>
</child>
</table>
</styles>
<data type="json">
{
"title": "Annual Report 2025",
"subtitle": "Meridian Holdings Group"
}
</data>
</press>Auto-Numbered Headings
Use <counter-define> to create named counters that increment automatically:
xml
<components>
<h1 outline="sections">
<counter-define name="h1" />
<counter-define name="h2" value="0" />
<frame font-size="18pt" font-style="bold" space-after-desired="16pt">
<counter-value name="h1" /> <slot />
</frame>
</h1>
<h2 outline="sections" level="2">
<counter-define name="h2" />
<frame font-size="14pt" font-style="bold" space-after-desired="12pt">
<counter-value name="h1" />.<counter-value name="h2" /> <slot />
</frame>
</h2>
</components>This produces numbered headings like "1 Introduction", "1.1 Background", "2 Methodology", etc. The value="0" on the counter named "h2" in the "h1" definition resets the sub-counter each time a new h1 is encountered.