pdg XML → PDF

The pdg book · Chapter 09 of 10 · Across the page break

Multi-page documents

How pdg flows content across pages, and the page furniture that frames every one — running headers and footers, page numbers, and PDF outline bookmarks.

So far our examples have fit on a page. Real documents do not, and this is where pdg earns its keep: long content flows across pages automatically, and you can frame every page with a repeating header and footer.

How content breaks across pages

You never insert page breaks by hand. When pdg lays out an element and it does not all fit, the element reports back how much did fit and hands over the rest; the engine starts a fresh page and continues. A long <text> splits between lines, a <list> between items, a <table> between rows — all through one mechanism.

If you want the precise contract behind this — the "fits / partly fits / doesn't fit" protocol every element obeys — it is documented in the layout protocol. The practical upshot for you is simple:

  • Almost everything splits. A plain <text> continues line by line, a <list> by items, a <table> by rows. Even a decorated block does: a <box> (or any element with style:padding/background/border) fragments across the break, redrawing its border around each piece — the top edge stays with the first fragment, the bottom with the last, so the two read as one box severed by the break. You met this in the box model chapter.
  • keep="true" forces a block to stay whole. When a card or callout should never straddle a break, add keep="true" and the whole block moves to the next page instead of splitting. A box pinned to a fixed style:height is the other way to stop a split — it can't grow onto a second page, so overflow is clipped rather than carried.

Page templates: headers and footers on every page

A header that repeats on page after page is not content you put in a <page> — it would only appear once. Instead you declare a <layout> template, a direct child of <document> alongside <config> and <pages>. Inside it, <content/> marks where each page's flowed content drops in. Everything before <content/> is the running header; everything after is the running footer.

Try it — edit the source Open in Playground
<document version="2.0">
  <config><page size="A6" margin="20px" /></config>
  <layout>
    <horizontal cross="center">
      <text bold="true" size="11">Field Notes</text>
      <expander />
      <text size="9" color="#847d6c">June 2026</text>
    </horizontal>
    <line stroke="#ddd5c4" style:margin="5px 0 0 0" />
    <content />
    <line stroke="#ddd5c4" />
    <horizontal main="center">
      <text size="9" color="#847d6c"><field name="page"/> of <field name="pages"/></text>
    </horizontal>
  </layout>
  <pages>
    <page>
      <text size="13">The title bar above and the page number below are the
        template. They would repeat on every page; I just flow into the content
        slot between them.</text>
    </page>
  </pages>
</document>

Notice the <expander/> in the header pushing the date to the right edge — the spring from Chapter 6, doing real work.

Page numbers

Page numbers are inline markup, not a block of their own. A <field> sits inside a <text>, like <b> or <font>, and is swapped for a document value at layout time: <field name="page"/> is the current page, <field name="pages"/> the total. You write the words around it — "Page", "of", "—" — as ordinary text:

Try it — edit the source Open in Playground
Page <field name="page"/>

The field inherits the run's size, color, and font, so you style the enclosing <text>, never the field itself. The total (name="pages") is only known once the whole document is paginated, so it fills in on pages drawn from a <layout> template — exactly the footer above, which reads — <field name="page"/> of <field name="pages"/> —.

Per-page templates

A <layout> on an individual <page> overrides the document template for that page — and an empty <layout/> opts a page out of the template entirely, which is exactly what you want for a cover page with no header or footer.

Bookmarks: the PDF outline

<bookmark> drops an invisible anchor that becomes an entry in the PDF's outline — the clickable sidebar of sections a reader sees in their PDF viewer. Give it a title and a level to nest entries.

Try it — edit the source Open in Playground
<document version="2.0">
  <config><page size="A6" margin="20px" /></config>
  <pages>
    <page>
      <bookmark level="1" title="Introduction" />
      <text size="18" bold="true">Introduction</text>
      <text size="12">Open this PDF's outline panel and you'll find an
        "Introduction" entry pointing right here.</text>
      <bookmark level="2" title="Background" />
      <text size="15" bold="true">Background</text>
      <text size="12">A level-2 bookmark nests under the section above it.</text>
    </page>
  </pages>
</document>

Bookmarks add nothing visible to the page — they are pure navigation, and on a long report they are the difference between a wall of pages and a document a reader can move around in.

You now have every piece. Let's put them together into a real page.