Appearance
Data and Templating
Press separates content from presentation, and data is a key part of that separation. The <data> element lets you define structured information that can be referenced throughout your document using {{ }} expressions.
Defining Data
JSON Data
The most commonly used format. Use type="json":
xml
<data type="json">
{
"company": "Meridian Consulting",
"date": "15 January 2026",
"client": {
"name": "Helena Torres",
"title": "Operations Director"
},
"items": [
{ "description": "Strategy workshop", "hours": 8, "rate": 150 },
{ "description": "Implementation review", "hours": 4, "rate": 150 }
]
}
</data>CSV Data
For tabular content, use type="csv":
xml
<data type="csv" name="table-data">
Month,Revenue,Expenses
January,42000,31000
February,45000,29000
March,51000,33000
</data>The above CSV data is accessible as data.table-data, where each row is an object with column-name keys. If name is missing, the data can be accessed under data.rows.
XML Data
You can also define data using XML elements:
xml
<data>
<title>Quarterly Report</title>
<author>J. Hartfield</author>
<date>March 2026</date>
</data>Each child element becomes a data field: {{ data.title }}, {{ data.author }}, etc.
Referencing Data
Use {{ }} expressions to insert data values into your document:
In Text Content
xml
<h1>{{ data.title }}</h1>
<p>Prepared by {{ data.author }} on {{ data.date }}</p>In Attributes
xml
<img src="{{ data.logo }}" />
<frame width="{{ data.sidebar ? '60%' : '100%' }}">Nested Paths
Access nested objects with dot notation:
xml
<p>{{ data.client.name }}, {{ data.client.title }}</p>Array Items
Access array elements by index:
xml
<p>First item: {{ data.items[0].description }}</p>Ternary Expressions
Use the ternary operator for conditional values:
xml
{{ condition ? valueIfTrue : valueIfFalse }}Common patterns:
xml
<!-- Default value -->
<frame>{{ data.subtitle ? data.subtitle : 'No subtitle provided' }}</frame>
<!-- Conditional sizing -->
<frame width="{{ data.has-image ? '60%' : '100%' }}">
<!-- Conditional text -->
<span font-style="{{ data.urgent ? 'bold' : 'normal' }}">{{ data.status }}</span>Data Merging
When using templates with payloads (via the API or platform), both can include <data> elements. Press merges them:
Template data provides defaults:
xml
<!-- template.press -->
<data type="json">
{
"currency": "£",
"tax_rate": 20,
"company": "Default Corp"
}
</data>Payload data overrides on conflict:
xml
<!-- payload.press -->
<data type="json">
{
"company": "Meridian Consulting",
"client": "Helena Torres",
"total": 1800
}
</data>Result: currency and tax_rate come from the template, company uses the payload's value, and client and total are added from the payload.
Data in Assets
Define constant data in <assets> for values that should never be overridden by a payload. This is particularly useful for default, fall-back values, e.g.:
xml
<assets>
<data type="json">
{
"defaults": {
"currency": "$",
"logo": "https://example.com/logo.png",
"company": "Meridian Consulting"
}
}
</data>
</assets>Access with {{ assets.data.defaults.currency }}.
xml
<frame>{{ data.currency ? data.currency : assets.data.defaults.currency }}</frame>Data in Flows
Flows and flow group members can define their own <data> elements:
xml
<flows>
<group name="sections">
<overview type="markdown">
<data type="json">
{ "section-title": "Overview", "icon": "chart-bar" }
</data>
The business performed strongly across all segments...
</overview>
</group>
</flows>This data is accessible when iterating:
xml
<repeat group="sections" item="section">
<page>
<h1>{{ section.data.section-title }}</h1>
<flow name="section" />
</page>
</repeat>Example: A Complete Invoice
Here's how data powers a simple invoice:
xml
<press>
<document format="A4" page-margin="2cm">
<page>
<frame direction="row">
<frame width="50%">
<frame font-size="10pt">Invoice To:</frame>
<frame font-size="14pt" font-style="bold">{{ data.to.name }}</frame>
<frame font-size="10pt">{{ data.to.company }}</frame>
</frame>
<frame width="50%">
<frame font-size="10pt">Invoice From:</frame>
<frame font-size="14pt" font-style="bold">{{ data.from.name }}</frame>
<frame font-size="10pt">Date: {{ data.date }}</frame>
</frame>
</frame>
<table>
<tr>
<th width="50%">Description</th>
<th>Hours</th>
<th>Rate</th>
<th text-align="right">Total</th>
</tr>
<repeat data="data.items" item="line">
<tr>
<td>{{ line.description }}</td>
<td text-align="center">{{ line.hours }}</td>
<td text-align="center">{{ data.currency }}{{ line.rate }}</td>
<td text-align="right">{{ data.currency }}{{ line.total }}</td>
</tr>
</repeat>
</table>
<frame h-align="right" padding-top="12pt">
<frame font-style="bold" font-size="14pt">
Total: {{ data.currency }}{{ data.grand-total }}
</frame>
</frame>
</page>
</document>
<data type="json">
{
"currency": "£",
"date": "15 January 2026",
"to": { "name": "Helena Torres", "company": "Apex Industries" },
"from": { "name": "R. Whitfield", "company": "Meridian Consulting" },
"items": [
{ "description": "Strategy workshop", "hours": 8, "rate": 150, "total": 1200 },
{ "description": "Implementation review", "hours": 4, "rate": 150, "total": 600 }
],
"grand-total": 1800
}
</data>
</press>