Back to invoice templates

Branding

Logo, brand colors and typography in BlockTemplate. Instead of repeating color values and font sizes in every block, you define design tokens once in page and reference them — changing a single value updates the whole template.

Color and typography tokens flowing into an invoice

Logo

image block with src (URL, Base64 or placeholder). fit: [width, height] scales proportionally into the box.

Colors

colorScheme defines named tokens. Blocks reference them via { token: '…' } — one value updates every usage.

Fonts

defaultFont sets the default family. fontSizes tokens keep the typography scale consistent (body, heading, small, total).

Embedding a logo

As an image block with URL, Base64 data URI or placeholder. fit scales proportionally into a target box without distorting the aspect ratio.

json
1{
2 "type": "image",
3 "data": {
4 "src": "https://cdn.example.com/logo.png",
5 "fit": [120, 60],
6 "alignment": "right"
7 }
8}
9// Alternative: Base64 data URI for guaranteed offline rendering
10// "src": "data:image/png;base64,iVBORw0KGgoAAAANS..."

Defining design tokens

page.colorScheme and page.fontSizes hold named values. Names are free — semantic tokens like primaryColor or headingSize work well.

json
1{
2 "page": {
3 "size": "A4",
4 "margins": { "top": 40, "right": 40, "bottom": 40, "left": 40 },
5 "colorScheme": {
6 "primaryColor": "#4f46e5",
7 "accentColor": "#8b5cf6",
8 "textColor": "#111111",
9 "mutedColor": "#6b7280",
10 "lineColor": "#e5e7eb"
11 },
12 "fontSizes": {
13 "bodySize": 10,
14 "smallSize": 8,
15 "headingSize": 18,
16 "totalSize": 12
17 }
18 }
19}

Referencing tokens

Anywhere a block expects a color or size value, you can pass { token: '…' } instead.

json
1{
2 "type": "text",
3 "data": {
4 "content": "INVOICE {{invoiceNumber}}",
5 "fontSize": { "token": "headingSize" },
6 "color": { "token": "primaryColor" },
7 "bold": true
8 }
9}
10 
11{
12 "type": "table",
13 "data": {
14 "dataSource": "{{items}}",
15 "headerFillColor": { "token": "primaryColor" },
16 "headerTextColor": "#FFFFFF",
17 "fontSize": { "token": "bodySize" },
18 "columns": [ /* ... */ ]
19 }
20}

Named styles for recurring elements

The styles object bundles font, color and margin presets. Blocks reference them via the style property. Design tokens are allowed here too.

json
1{
2 "styles": {
3 "h1": { "fontSize": 22, "bold": true, "color": { "token": "primaryColor" } },
4 "h2": { "fontSize": 14, "bold": true, "margin": [0, 0, 0, 6] },
5 "muted": { "color": { "token": "mutedColor" } },
6 "total": { "fontSize": 14, "bold": true, "alignment": "right" }
7 }
8}
9 
10// Blocks reference styles by name:
11{ "type": "text", "data": { "content": "INVOICE", "style": "h1" } }

Header & footer

header and footer are optional. With repeatOnAllPages: true they appear on every page; otherwise only on the last. Both accept the same 9 block types as body.

json
1{
2 "header": {
3 "height": 80,
4 "repeatOnAllPages": true,
5 "blocks": [
6 {
7 "type": "columns",
8 "data": {
9 "columns": [
10 { "width": "*", "blocks": [
11 { "type": "text", "data": { "content": "{{seller.name}}", "style": "h2" } }
12 ]},
13 { "width": "auto", "blocks": [
14 { "type": "image", "data": { "src": "https://cdn.example.com/logo.png", "fit": [120, 60] } }
15 ]}
16 ]
17 }
18 }
19 ]
20 },
21 "footer": {
22 "repeatOnAllPages": true,
23 "blocks": [
24 { "type": "line", "data": { "thickness": 0.5, "color": { "token": "lineColor" } } },
25 { "type": "text", "data": {
26 "content": "{{seller.name}} • USt-IdNr. {{seller.vatId}} • {{seller.email?}}",
27 "fontSize": { "token": "smallSize" },
28 "color": { "token": "mutedColor" },
29 "alignment": "center"
30 }}
31 ]
32 }
33}