Combine templates
Build one document from several templates: a cover before the invoice, terms and conditions after it, a letterhead or a “DRAFT” watermark on every page, a table of contents, or a section name on each page. Each part is an ordinary template in the same workspace, so you design it once and reuse it everywhere. A part can also be a PDF file you upload, such as a supplier’s terms or a form your template fills in; see add an uploaded PDF file.
{ "operations": [ { "type": "prepend", "template": "Cover" }, { "type": "append", "template": "Terms" }, { "type": "merge", "template": "Letterhead" } ]}With these steps, a render of the invoice returns the cover, the invoice and the terms in one PDF, with the letterhead drawn beneath the content of every page.
Add pages before or after
Section titled “Add pages before or after”-
Create the other template, such as
Terms, and publish it. -
In the template that adds it, click PDF properties in the preview toolbar. Under Other templates and PDF files, click Add template.
-
Choose the template, then choose what to do with it:
Studio typeWhat it does Add its pages before prependAdds all its pages before the document’s pages, such as a cover. Add its pages after appendAdds all its pages after them, such as terms and conditions. Draw it onto every page mergeDraws it onto the document’s pages. See draw onto every page. -
Click Update preview to see the added pages, then save and publish the template.
Studio writes each step to the operations list in the template’s page.json, and you can
edit that list there instead.
Draw onto every page
Section titled “Draw onto every page”A merge step draws the other template onto the document’s pages, beneath the content, like
printed letterhead paper. Its first page is drawn onto every page, at its own size from the
page’s top-left corner, so give it the same paper size as the document.
For a step that draws, tick any of these in Studio:
| Studio | Field | What it does |
|---|---|---|
| Page by page | mergeWholeDocument |
Draws its page 1 onto page 1, its page 2 onto page 2, and so on. Pages beyond its last page get nothing. |
| Render for every page | renderForEveryPage |
Renders it once for each page, so it can show that page’s details. See print something on each page. Not with Page by page. |
| In front of the content | mergeToFront |
Draws it over the content instead of beneath it. |
A watermark is a template drawn in front of the content. Make a template named Watermark with
no margins:
{ "pageSize": { "widthMm": 210, "heightMm": 297 }, "margins": { "topMm": 0, "rightMm": 0, "bottomMm": 0, "leftMm": 0 }}<div style="height: 297mm; display: flex; align-items: center; justify-content: center;"> <div style="transform: rotate(-45deg); font-size: 120pt; color: #e11d48; opacity: 0.15;"> DRAFT </div></div>Then add it to the document as a step:
{ "type": "merge", "template": "Watermark", "mergeToFront": true }Steps run in the order listed, and a merge draws onto the pages the document has at that
point. Put it last to draw onto added pages too, or before them to leave the cover and terms
plain.
Add an uploaded PDF file
Section titled “Add an uploaded PDF file”A step can add a PDF file instead of a template, such as terms you received as a PDF. Add the
file to the template’s folder with Import into folder… in the folder’s … menu, then in
PDF properties under Other templates and PDF files, click Add PDF file and choose it.
In page.json, the step names the file’s path with pdf instead of template:
{ "operations": [{ "type": "append", "pdf": "terms.pdf" }]}The path starts at the template’s folder, like the template’s other
workspace files. Every step type works with a file: prepend and
append add all its pages, and merge draws its first page, or with mergeWholeDocument its
page N onto page N. A file has no data to fill in, so renderForEveryPage does not apply.
Fill in a supplier’s form
Section titled “Fill in a supplier’s form”To fill in a PDF form you received, draw it beneath your document page by page. Make a template with the form’s paper size and no margins, and place each value where the form has its box:
<div style="position: relative; height: 297mm;"> <div style="position: absolute; top: 52mm; left: 40mm;">{{customer.name}}</div> <div style="position: absolute; top: 61mm; left: 40mm;">{{orderNumber}}</div></div>Then draw the form beneath it:
{ "pageSize": { "widthMm": 210, "heightMm": 297 }, "margins": { "topMm": 0, "rightMm": 0, "bottomMm": 0, "leftMm": 0 }, "operations": [{ "type": "merge", "pdf": "forms/order-form.pdf", "mergeWholeDocument": true }]}The document keeps its own pages, so give the template one page for each page of the form: a form page with no page of the template to draw onto is left out. The form’s own fillable fields are not filled in; your template draws the values over them.
Use the document’s pages in the other template
Section titled “Use the document’s pages in the other template”The other template can read $pdf, the document’s pages as they are when its step runs, to
print a table of contents or details that change from page to page.
In the document, mark where each section starts with pdfCreatePagesGroup, and add a link
target with pdfDest. Print both with triple braces:
{{#each sections}} <h2>{{title}}{{{pdfCreatePagesGroup title=title id=id}}}{{{pdfDest id}}}</h2> <p>{{body}}</p>{{/each}}The other template then has:
| Field | What it holds |
|---|---|
$pdf.pages |
One entry per page of the document so far. Each has group, the value of the last pdfCreatePagesGroup on or before that page, and items, the values of pdfAddPageItem on that page. |
$pdf.pageIndex |
With Render for every page: the page it is drawn onto, from 0. |
$pdf.pageNumber |
With Render for every page: the same page, from 1. |
| Helper | What it does |
|---|---|
{{{pdfCreatePagesGroup value}}} |
Sets the group of the page it is on, and of the pages after it until the next group. The value can be any data, or hash arguments as above. |
{{{pdfAddPageItem value}}} |
Adds the value, or the hash arguments, to the items of the page it is on. |
{{{pdfDest "name"}}} |
Marks a place that a #name link in any part of the document leads to. See link between parts. |
Keep these helpers out of elements with display: inline-block, where they are not found.
The other template still gets the document’s data, with $pdf added. Read $pdf in its HTML,
its page header and footer, or its helpers.js. Its scripts run before
the pages exist, so they cannot read it, and only an HTML template can read it, not a component
template.
Print a table of contents
Section titled “Print a table of contents”Make a template named Contents that lists the first page of each group. In its helpers.js:
function sections(pages, offset) { const result = [];
pages.forEach((page, index) => { const last = result[result.length - 1];
if (page.group !== undefined && (last === undefined || last.id !== page.group.id)) { result.push({ ...page.group, page: index + 1 + offset }); } });
return result;}<h1>Contents</h1><ul> {{#each (sections $pdf.pages 1)}} <li><a href="#{{id}}">{{title}}</a>, page {{page}}</li> {{/each}}</ul>Add it to the document with Add its pages before (prepend). The page numbers count the
document as it is before the contents are added, so offset adds the contents’ own length,
here one page.
Print something different on each page
Section titled “Print something different on each page”Add the other template with Draw it onto every page and tick Render for every page. It
renders once for each page, with $pdf.pageIndex and $pdf.pageNumber naming the page it is
drawn onto. This template prints the section name and a page number that restarts in each
section, at the bottom of every page:
function sectionPage(pages, index) { let start = index;
while (start > 0 && pages[start - 1].group?.id === pages[index].group?.id) { start -= 1; }
return index - start + 1;}<div style="height: 297mm; position: relative;"> <div style="position: absolute; bottom: 10mm; left: 18mm; right: 18mm; font-size: 9pt;"> {{#with (lookup $pdf.pages $pdf.pageIndex)}}{{group.title}}{{/with}}, page {{sectionPage $pdf.pages $pdf.pageIndex}} </div></div>Give it the document’s paper size and no margins, as for the watermark above. For a plain “Page 1 of 3” footer you need no other template: use the template’s own page footer, see build a template.
Link between parts
Section titled “Link between parts”Mark a place with {{{pdfDest "terms"}}} in one template, and link to it with
<a href="#terms"> from any template in the same document, such as from the invoice to its
terms. {{{pdfDest id="terms"}}} works too. A link to an id in the same template works as
usual, and a link to a name that no part defines is left as plain text.
- The other template renders with the same data and language as the document, on its own paper size, margins, page header and footer.
- Studio previews use the other template’s saved draft. Every other render uses its published version, so publish it first. When you publish a new version of it, every template that adds it uses that version from then on. See publishing.
- An uploaded PDF file is read when the document renders, so replacing the file changes every render from then on, without publishing again. Publishing checks that the file exists; if it is deleted or moved later, renders fail.
- An uploaded PDF file can be up to 5 MB, and it cannot be encrypted. It counts toward the render’s input size, and in a batch every document carries it, so a large file leaves room for fewer documents; see limits.
- Added pages from an uploaded file keep their look and their bookmarks, but not their fillable form fields or their links to named places inside the file.
- Templates are found by name, ignoring case. If none has that name, Studio warns under Other templates and PDF files and renders fail until one is created and published.
- A template can have up to 10 steps. A template that another one adds cannot have steps of its own, and a spreadsheet template cannot be added.
- Steps run only when you render a template: by name with the Reports API, or a template version with the Renders API. A render of raw HTML and a string render cannot have steps.
- A Reports API request can replace the template’s steps with
pdf.operations, and an empty list runs none. See the API reference. - The added pages count toward the page limit; see limits.
- If the other template or PDF file fails, the error message names it.
- A PDF/A or PDF/UA document keeps its standard with parts from other templates. In a PDF/UA document, pages added before or after keep their headings and bookmarks, and a drawn template is decoration that screen readers skip. See PDF standards.
- A PDF/A or PDF/UA document cannot add an uploaded PDF file, since nothing checks that the file meets the standard. Rebuild that part as a template instead.