Build a template
Build an invoice template in Studio: A4 paper with margins, a header and a “Page 1 of 2” footer on every page, page breaks where you want them, your own font and a logo. Then preview it with sample data and publish it so your application can render it.
Before you start: you need a Studio sign-in to a workspace.
1. Create the template
Section titled “1. Create the template”- In the Studio sidebar, click Workspace → Editor. The editor opens in a new browser tab.
- In the explorer on the left, click + and choose New folder. Enter
Invoicesas the Folder name and click Create folder. - Click ⋯ on the Invoices folder (or right-click it) and choose New entity → Template.
- Enter
Invoiceas the Template name, leave Start with on Blank template, and click Create template.
The editor opens the template’s template.html.
2. Write the HTML
Section titled “2. Write the HTML”Replace everything in template.html with this:
<html> <head> <style> body { font-family: sans-serif; } table { width: 100%; border-collapse: collapse; } th, td { border-bottom: 1px solid #ccc; padding: 4px; text-align: left; } </style> </head> <body> <h1>Invoice {{invoice.number}}</h1> <p>Bill to: {{customer.name}}</p>
<table> <thead> <tr><th>Item</th><th>Qty</th><th>Price</th></tr> </thead> <tbody> {{#each lines}} <tr> <td>{{description}}</td> <td>{{quantity}}</td> <td>{{price}}</td> </tr> {{/each}} </tbody> </table> </body></html>The placeholders, such as {{customer.name}} and {{#each lines}}, use
Handlebars syntax and are filled from your data. Press
Ctrl+S (Cmd+S on macOS) or click Save.
3. Add sample data
Section titled “3. Add sample data”Sample data is the JSON Studio uses for previews.
-
Click ⋯ on the Invoices folder and choose New entity → Sample data.
-
Enter
sample.jsonas the Name and click Create entity. -
Click
sample.jsonin the explorer to open it, replace{}with this, and save:sample.json {"invoice": { "number": "INV-1001" },"customer": { "name": "Marta Tamm" },"lines": [{ "description": "Consulting", "quantity": 3, "price": 120 },{ "description": "Travel", "quantity": 1, "price": 80 }]} -
Click the Invoice template in the explorer to go back to it.
4. Set the paper size and margins
Section titled “4. Set the paper size and margins”Click the page.json tab under the HTML and set the paper and margins in millimetres. Leave room at the top and bottom for the header and footer:
{ "pageSize": { "widthMm": 210, "heightMm": 297 }, "orientation": "portrait", "margins": { "topMm": 32, "rightMm": 18, "bottomMm": 22, "leftMm": 18 }}You can also pick Paper and Margins under PDF properties in the preview toolbar,
which writes the same page.json. For landscape, keep the portrait size and set
"orientation": "landscape". Every setting is in page.json.
5. Add a header and footer with page numbers
Section titled “5. Add a header and footer with page numbers”The header is drawn in the top margin of every page, and the footer in the bottom margin.
-
Click + at the end of the tabs under the HTML and choose Add page header. In the Page header tab (
header.html), add:header.html <div style="flex: 1; padding: 10mm 18mm 0; font-size: 9pt;">Invoice{{invoice.number}}</div> -
Click + again and choose Add page footer. In the Page footer tab (
footer.html), add elements with the classespageNumberandtotalPages. They are filled with the current page and the page count:footer.html <div style="flex: 1; padding: 0 18mm 8mm; font-size: 8pt; text-align: right;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>
The header and footer use the same data and helpers as the HTML. They span the full page width,
so the side padding above lines them up with the 18 mm margins. They must fit inside the margin,
which does not grow: if the header is cut off, raise topMm. Style them with inline style
attributes, because a <style> element in them applies to the whole document. The other rules
are in Supported CSS.
6. Control where pages break
Section titled “6. Control where pages break”Content flows onto the next page on its own. To keep an element in one piece, or to start it on
a new page, add CSS to the <style> element in template.html:
/* Never split a table row across two pages. */tr { break-inside: avoid;}
/* Start the terms on a new page. */.terms { break-before: page;}For every supported break property, see Supported CSS.
7. Use your own font
Section titled “7. Use your own font”Text is set in fonts bundled with Typefold until you upload and declare your own. Fonts installed on the server or loaded from a URL are never used.
-
Click ⋯ on the Invoices folder, choose New folder and create a
fontsfolder. -
Click ⋯ on the
fontsfolder and choose New entity → Asset. Choose the font files (TTF, OTF or WOFF2) and click Upload assets. -
In the
<style>element oftemplate.html, declare each file with@font-face, one rule per weight, and use the family onbodyin place ofsans-serif:@font-face {font-family: "Inter";src: url("fonts/Inter-Regular.ttf");font-weight: 400;}@font-face {font-family: "Inter";src: url("fonts/Inter-Bold.ttf");font-weight: 700;}body {font-family: "Inter", Arial;}
url() paths start from the folder of the file they are written in. From a stylesheet in a
styles folder, the same font is url("../fonts/Inter-Regular.ttf").
If no font covers a character, such as Chinese text, the render fails with ASSET_INVALID.
Upload a font that covers it.
8. Add a logo
Section titled “8. Add a logo”-
Create an
imagesfolder in Invoices and upload the logo (PNG, JPEG or SVG) the same way. -
Point to it by path, in
template.htmlor in the header:<img src="./images/logo.svg" alt="Logo" style="height: 12mm" />
Images at an https:// address are not loaded, so always upload them.
9. Preview the document
Section titled “9. Preview the document”- In the preview toolbar, set Data to
sample.json. - Click Update preview.
The PDF appears beside the source: A4 pages in Inter, with the logo, “Invoice INV-1001” in the
header, a two-row table and “Page 1 of 1” in the footer. Click Update preview again after
each change. Save the template to keep sample.json as its preview data.
10. Publish
Section titled “10. Publish”Click Save, then Publish in the header. The status changes to Published v1. Your
application can now render the template by its name, Invoice, with the
Reports API.
A published version keeps its own copy of every file, so later edits to the template, its fonts or its images reach your application only when you publish again. See Templates.
Next steps
Section titled “Next steps”- Render a report by name: send your own data to
Invoicefrom your app. - Handlebars templates: helpers, scripts and shared files.
- Translations and formatting: money, dates and languages.
- Combine templates: add a cover, terms or a letterhead.
- Supported CSS: every layout rule, including CSS
@page.