Dynamic tables
Variable rows, header styles and automatic pagination.
Invoices, quotes and delivery notes have a line-items table whose length you don't know in advance. A table variable in a PDF template takes an array of row objects at render time — one object per line — instead of a single string.
Pass an array, not a string
A table variable is filled by the same render call; its value is an array of objects keyed by the template's column keys:
curl -X POST https://api.pdf-forge.dev/v1/pdf-templates/$TEMPLATE_ID/render \
-H "Authorization: Bearer $PDFFORGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"variables": {
"client_name": "ACME Corp",
"items": [
{ "label": "Consulting", "qty": "3", "price": "150,000" },
{ "label": "Hosting", "qty": "1", "price": "50,000" },
{ "label": "Support", "qty": "12", "price": "10,000" }
]
}
}' \
--output invoice.pdfconst pdf = await client.pdfTemplates.render(templateId, {
client_name: "ACME Corp",
items: [
{ label: "Consulting", qty: "3", price: "150,000" },
{ label: "Hosting", qty: "1", price: "50,000" },
{ label: "Support", qty: "12", price: "10,000" },
],
});Each object's keys match the columns defined on the table when the template was built. Cells map by key, so column order in your JSON doesn't matter.
Two kinds of table
How the rows land depends on how the table was marked in the editor:
| Table kind | Behaviour |
|---|---|
| Region table (drawn as a table region) | The grid is redrawn for exactly the number of rows you pass — dynamic height, optional row reflow across the page, header background, zebra striping and per-column alignment come from the template. |
| Fixed grid (existing physical rows marked) | Rows are filled positionally: item i fills physical row i, and any extra rows are cleared. Capacity equals the number of rows in the original PDF (a static grid can't reflow). |
A PDF can't reflow on its own
Only the region-table kind grows or shrinks to fit the data. On a fixed grid, sending more items than there are physical rows means the surplus is dropped — size the source PDF for your worst case, or use a region table.
Omitted values
Skip the table variable entirely and the template keeps its stored default rows. Send fewer objects than the grid has rows and the leftover rows are blanked.
Next steps
- Render via API — the full render call and scalar variables.
- Import a PDF — mark the table region in the editor.
- MCP server — fill templates from an agent.