Skip to main content
page.header and page.footer are nodes that repeat on every page — at the top and bottom respectively. Both are optional, and each is an ordinary node, so anything you can put in the body goes there too.
{
  "page": {
    "header": { "type": "row", "items": [ "...branding..." ] },
    "content": { "type": "column", "items": [ "...the document..." ] },
    "footer": { "type": "richText", "align": "center", "spans": [ "...page numbers..." ] }
  }
}
The body flows between them. On a multi-page document the header and footer are redrawn on each page, and the content area shrinks to leave room — you don’t position them yourself.

A branded header

A header is usually a row: the brand on the left, document metadata on the right.
{
  "type": "row",
  "items": [
    { "size": { "kind": "relative", "weight": 1 }, "child": { "type": "column", "items": [
      { "type": "text", "value": "{{brand.name}}", "style": { "fontSize": 18, "bold": true } },
      { "type": "text", "value": "{{brand.tagline}}", "style": { "fontSize": 9, "color": "grey.darken1" } }
    ] } },
    { "size": { "kind": "constant", "width": 180 }, "child": { "type": "column", "items": [
      { "type": "text", "value": "INVOICE", "style": { "fontSize": 20, "bold": true }, "align": "right" },
      { "type": "text", "value": "{{invoice.number}}", "style": { "color": "grey.darken2" }, "align": "right" }
    ] } }
  ]
}

Page numbers

Page numbers come from a richText node using the pageNumber and totalPages spans. Put it in the footer (or header) so it repeats and resolves per page:
{
  "type": "richText",
  "align": "center",
  "spans": [
    { "value": "Page ", "style": { "fontSize": 9, "color": "grey.darken1" } },
    { "pageNumber": true },
    { "value": " of ", "style": { "fontSize": 9, "color": "grey.darken1" } },
    { "totalPages": true }
  ]
}
That renders Page 1 of 3, Page 2 of 3, and so on. pageNumber and totalPages are filled in by the renderer — they’re the only dynamic values that don’t come from your data.
Page-number spans only do something useful where the node repeats. In page.content they’d render a single time on the first page. Keep them in header or footer.
Not every footer needs page numbers. A one-line legal/contact footer is just a text node:
{
  "type": "text",
  "value": "{{company.name}} · {{company.email}} · Payable within 14 days",
  "style": { "fontSize": 8, "color": "grey.darken1" },
  "align": "center"
}

See it in a multi-page document

The report example combines a repeating header, a long auto-paginating table, and a page-number footer.