04. Headers, Footers, And Page Control

VMPrint supports running page regions and a few important pagination controls.

Header and footer

header and footer are page regions, not ordinary body flow.

Use strip for most running-head and folio compositions. It is a better fit than table for logo-plus-title headers or page x of y footers.

{
  "header": {
    "firstPage": null,
    "default": {
      "elements": [
        {
          "type": "strip",
          "stripLayout": {
            "tracks": [
              { "mode": "fixed", "value": 18 },
              { "mode": "flex", "fr": 1 }
            ],
            "gap": 8
          },
          "slots": [
            {
              "elements": [
                {
                  "type": "image",
                  "image": {
                    "mimeType": "image/png",
                    "fit": "contain",
                    "data": "data:image/png;base64,..."
                  },
                  "properties": { "style": { "width": 14, "height": 14 } }
                }
              ]
            },
            { "elements": [{ "type": "header-title", "content": "Acme Corp - Quarterly Report" }] }
          ]
        }
      ]
    }
  },
  "footer": {
    "default": {
      "elements": [
        {
          "type": "strip",
          "stripLayout": {
            "tracks": [
              { "mode": "flex", "fr": 1 },
              { "mode": "fixed", "value": 40 },
              { "mode": "flex", "fr": 1 }
            ],
            "gap": 8
          },
          "slots": [
            { "elements": [{ "type": "footer-left", "content": "VMPRINT QUARTERLY" }] },
            { "elements": [{ "type": "footer-page", "content": "Page {pageNumber} of {totalPages}" }] },
            { "elements": [{ "type": "footer-right", "content": "vmprint.dev" }] }
          ]
        }
      ]
    }
  }
}

Keep-with-next

Use keepWithNext when a heading should not be stranded away from its first paragraph.

{
  "type": "section-head",
  "content": "Observation 01",
  "properties": {
    "keepWithNext": true
  }
}

Page breaks

Use pageBreakBefore sparingly when a new section truly needs a fresh page.

{
  "type": "chapter-head",
  "content": "Part Two",
  "properties": {
    "pageBreakBefore": true
  }
}

Odd-sized pages

Use layout.pageTemplates when a document needs pages with different physical dimensions or margins. Templates are matched per page before layout, so the engine measures body flow, headers, footers, overlays, and debug geometry against the active page size.

{
  "layout": {
    "pageSize": { "width": 460, "height": 360 },
    "margins": { "top": 32, "right": 32, "bottom": 32, "left": 32 },
    "pageTemplates": [
      {
        "pageIndex": 1,
        "pageSize": { "width": 280, "height": 420 },
        "margins": { "top": 34, "right": 22, "bottom": 34, "left": 22 }
      },
      {
        "pageIndex": 2,
        "pageSize": { "width": 420, "height": 230 },
        "margins": { "top": 20, "right": 44, "bottom": 20, "left": 44 }
      }
    ]
  }
}

pageIndex is zero-based: 1 means the second physical page. You can also use selectors such as "first", "odd", "even", and "all" for broader rules; later templates refine earlier matches.

Page numbering

In headers and footers, token replacement happens automatically for values like:

Use page regions for repeated composition; keep ordinary document content in elements.

Partial simulation

The engine can stop layout after a requested page. This is useful for previews, incremental flow APIs, and tools that only need to inspect the first part of a document.

const pages = await engine.layout({ stopAtPage: 1 });

stopAtPage is also zero-based and inclusive, so 1 produces pages 0 and 1 when the document reaches that far. The simulation report records the stop as "page-limit"; this distinguishes an intentional prefix run from a complete document.

Next: