Packing slip
Build the packing slip that goes in the box. You learn to cap the number of rows, clip a long product name to one line, and put a small picture inside a cell.
What this teaches
Building it in the editor
- Build a repeating table and set the maximum rows. Rows past the cap are dropped and reported in warnings — cutting silently would leave items out of the box.
- A long product name wraps and pushes the table past the page. Turn table wrapping off to keep one line, clipping the overflow with an ellipsis.
- We never let overflow simply spill: on paper it prints on top of the neighbouring cell, and that does not look like an error.
- To bring wrapping back for one cell, select it and turn cell wrapping on. A cell setting always wins.
- In a hand-built grid a cell can hold a picture. Use it for small icons such as handling marks.
- Build the address block as labels inside a rectangle. Moving the parent moves everything inside, so you can reposition the block in one go.
Building it with the schema and API
- props.max is the maximum number of rows this table draws. 0 means no cap of yours, but ours still applies — 500 rows for a single table, and 2,000 rows for all tables in one render combined. With several tables the combined limit bites first, so do not size a document by looking at one table. Anything past it is dropped and reported in warnings.
- props.wrap set to "off" clips the whole table to one line. Bring it back on a cell with cells[].wrap set to "on".
- cells[].src accepts only values starting with data:image/. In a cell we do not throw: that one cell is left empty with a warning, so a single picture never costs you the whole slip.
The finished document
The JSON below is exactly the document those two routes produce. Our tests validate it and check that it renders without warnings, so you can paste it and use it as is.
{
"v": 1,
"unit": "px",
"page": {
"size": "a4",
"orientation": "portrait",
"margin": {
"t": 48,
"r": 48,
"b": 56,
"l": 48
},
"header": "",
"footer": "{{ data.order }} · [[page]] / [[pages]]"
},
"fonts": [],
"styles": [
{
"id": "s_h1",
"fontFamily": "Liberation Sans",
"fontSize": 22,
"fontWeight": 700,
"italic": false,
"color": "#111111",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_l",
"fontFamily": "Liberation Sans",
"fontSize": 12,
"fontWeight": 400,
"italic": false,
"color": "#333333",
"bg": "transparent",
"align": "left",
"valign": "top",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
},
{
"id": "s_tbl",
"fontFamily": "Liberation Sans",
"fontSize": 11,
"fontWeight": 400,
"italic": false,
"color": "#111111",
"bg": "transparent",
"align": "left",
"valign": "middle",
"lineHeight": 1.5,
"border": "none",
"radius": 0,
"opacity": 1
}
],
"nodes": [
{
"id": "n_title",
"parent": "",
"order": 0,
"type": "label",
"x": 0,
"y": 0,
"w": 400,
"h": 28,
"show": "",
"styleId": "s_h1",
"props": {
"text": "Packing slip",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Title"
},
{
"id": "n_addr",
"parent": "",
"order": 1,
"type": "rect",
"x": 400,
"y": 0,
"w": 297,
"h": 96,
"show": "",
"styleId": "s_l",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 1,
"stroke": "#dfe3e8",
"fill": "#fafbfc",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Ship-to block"
},
{
"id": "n_addr_1",
"parent": "n_addr",
"order": 2,
"type": "label",
"x": 12,
"y": 10,
"w": 273,
"h": 18,
"show": "",
"styleId": "s_l",
"props": {
"text": "{{ data.shipTo.name }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Recipient"
},
{
"id": "n_addr_2",
"parent": "n_addr",
"order": 3,
"type": "label",
"x": 12,
"y": 30,
"w": 273,
"h": 0,
"show": "",
"styleId": "s_l",
"props": {
"text": "{{ data.shipTo.address }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Address"
},
{
"id": "n_addr_3",
"parent": "n_addr",
"order": 4,
"type": "label",
"x": 12,
"y": 70,
"w": 273,
"h": 18,
"show": "",
"styleId": "s_l",
"props": {
"text": "Order {{ data.order }}",
"src": "",
"fit": "",
"thickness": 0,
"stroke": "",
"fill": "",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 0,
"padX": 0,
"align": "",
"valign": "",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 0,
"max": 0,
"columns": [],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Order number"
},
{
"id": "n_items",
"parent": "",
"order": 5,
"type": "table",
"x": 0,
"y": 120,
"w": 697,
"h": 220,
"show": "",
"styleId": "s_tbl",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 1,
"stroke": "#c9ced6",
"fill": "#f3f5f7",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 5,
"padX": 8,
"align": "",
"valign": "middle",
"wrap": "off",
"bind": "data.items",
"headerHeight": 26,
"rowHeight": 22,
"max": 40,
"columns": [
{
"header": "SKU",
"cell": "{{ item.sku }}",
"width": 140,
"align": "left"
},
{
"header": "Product",
"cell": "{{ item.name }}",
"width": 397,
"align": "left"
},
{
"header": "Qty",
"cell": "{{ item.qty }}",
"width": 160,
"align": "right"
}
],
"rows": 0,
"cells": [],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Line items"
},
{
"id": "n_care",
"parent": "",
"order": 6,
"type": "table",
"x": 0,
"y": 360,
"w": 340,
"h": 90,
"show": "",
"styleId": "s_tbl",
"props": {
"text": "",
"src": "",
"fit": "",
"thickness": 1,
"stroke": "#c9ced6",
"fill": "#f3f5f7",
"repeat": "",
"as": "",
"break": "",
"keep": "",
"padding": 0,
"padY": 8,
"padX": 10,
"align": "",
"valign": "middle",
"wrap": "",
"bind": "",
"headerHeight": 0,
"rowHeight": 44,
"max": 0,
"columns": [
{
"header": "",
"cell": "",
"width": 110,
"align": "center"
},
{
"header": "",
"cell": "",
"width": 230,
"align": "left"
}
],
"rows": 2,
"cells": [
{
"r": 0,
"c": 0,
"span": 1,
"rowspan": 1,
"text": "",
"align": "left",
"valign": "",
"wrap": "",
"pad": -1,
"padY": -1,
"padX": -1,
"src": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAgNjAiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iNjAiIHJ4PSI4IiBmaWxsPSIjMWYyOTM3Ii8+PHRleHQgeD0iNjAiIHk9IjM4IiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIyMCIgZmlsbD0iI2ZmZiIgdGV4dC1hbmNob3I9Im1pZGRsZSI+TE9HTzwvdGV4dD48L3N2Zz4=",
"fit": "contain",
"bg": "#ffffff",
"head": false,
"border": ""
},
{
"r": 0,
"c": 1,
"span": 1,
"rowspan": 1,
"text": "Handle with care — do not lay the box flat.",
"align": "left",
"valign": "",
"wrap": "",
"pad": -1,
"padY": -1,
"padX": -1,
"src": "",
"fit": "",
"bg": "",
"head": true,
"border": ""
},
{
"r": 1,
"c": 0,
"span": 1,
"rowspan": 1,
"text": "↑",
"align": "center",
"valign": "",
"wrap": "",
"pad": -1,
"padY": -1,
"padX": -1,
"src": "",
"fit": "",
"bg": "",
"head": false,
"border": ""
},
{
"r": 1,
"c": 1,
"span": 1,
"rowspan": 1,
"text": "This side up.",
"align": "left",
"valign": "",
"wrap": "",
"pad": -1,
"padY": -1,
"padX": -1,
"src": "",
"fit": "",
"bg": "",
"head": false,
"border": ""
}
],
"chartKind": "",
"codeKind": "",
"ecc": "",
"fieldKind": "",
"fieldName": "",
"options": [],
"required": false,
"readonly": false,
"html": ""
},
"name": "Handling"
}
]
}The request body. Put the document above into template and the data below into data.
{
"template": "(the document above)",
"data": {
"order": "SO-2026-8841",
"shipTo": {
"name": "Hanbit Corp. warehouse",
"address": "118 Seongsui-ro, Seongdong-gu, Seoul, 3F"
},
"items": [
{
"sku": "BM-0001",
"name": "brewmypdf mug (white, 350ml, individually boxed)",
"qty": 12
},
{
"sku": "BM-0002",
"name": "Sticker set",
"qty": 40
},
{
"sku": "BM-0003",
"name": "Notebook A5",
"qty": 25
}
]
}
}