Skip to content

Repeating Content

The <repeat> directive lets you generate elements from data arrays, iterate over flow groups, or repeat pages until a flow is consumed. It's how Press turns a single template into a multi-page, data-driven document.

Repeating Over Data

The most common use: iterate over an array and render elements for each item.

xml
<repeat data="data.team" item="person">
  <frame direction="row" space-after-desired="8pt">
    <frame width="fill">
      <frame font-style="bold">{{ person.name }}</frame>
      <frame font-size="9pt" font-color="#6b7280">{{ person.role }}</frame>
    </frame>
    <frame>{{ person.email }}</frame>
  </frame>
</repeat>

Attributes

AttributeRequiredDescription
dataYesPath to the array to iterate over
itemNoVariable name for each element (defaults to item)

If you omit item, the current element is accessible as item:

xml
<repeat data="data.tags">
  <span>{{ item }}</span>
</repeat>

Generating Table Rows

A common pattern -- generate table rows from data:

xml
<table>
  <tr>
    <th>Product</th>
    <th text-align="center">Quantity</th>
    <th text-align="right">Price</th>
  </tr>
  <repeat data="data.products" item="product">
    <tr>
      <td>{{ product.name }}</td>
      <td text-align="center">{{ product.qty }}</td>
      <td text-align="right">£{{ product.price }}</td>
    </tr>
  </repeat>
</table>

Nested Repeats

Use different item names to nest repeats:

xml
<repeat data="data.departments" item="dept">
  <h2>{{ dept.name }}</h2>
  <repeat data="dept.members" item="person">
    <p>{{ person.name }} - {{ person.title }}</p>
  </repeat>
</repeat>

Combining Repeat with show-if

Use show-if inside a repeat to conditionally render items:

xml
<repeat data="data.contacts" item="contact">
  <frame direction="row" space-after-desired="4pt">
    <frame width="fill" font-style="bold">{{ contact.name }}</frame>
    <frame show-if="contact.phone">{{ contact.phone }}</frame>
  </frame>
</repeat>

Repeating Over Flow Groups

When flows are organized into groups, use <repeat group="..."> to iterate over them:

xml
<flows>
  <group name="chapters">
    <introduction type="markdown">
      <data type="json">{ "title": "Introduction" }</data>
      Our research focused on three key areas...
    </introduction>
    <analysis type="markdown">
      <data type="json">{ "title": "Analysis" }</data>
      The data reveals clear patterns...
    </analysis>
  </group>
</flows>
xml
<document format="A4" page-margin="2cm">
  <repeat group="chapters" item="chapter">
    <page>
      <h1>{{ chapter.data.title }}</h1>
      <flow name="chapter" />
    </page>
  </repeat>
</document>

Each group member's <data> is accessible through the item variable's .data property.

Repeating Pages for a Flow

Use <repeat flow="..."> to generate as many pages as needed to consume a flow. This is only usable in the <document> tag:

xml
<document format="A4" page-margin="2cm">
  <repeat flow="body">
    <page>
      <flow name="body" />
    </page>
  </repeat>
</document>

Press generates pages until all content in the body flow has been rendered.

Alternating Page Types

Put multiple pages inside a flow repeat for alternating layouts:

xml
<repeat flow="body">
  <odd-page />
  <even-page />
</repeat>

Generating Pages from Data

Combine <repeat data="..."> at the document level to create one page per data item:

xml
<document format="A4" page-margin="1.5cm">
  <repeat data="data.employees" item="employee">
    <page>
      <h1>{{ employee.name }}</h1>
      <frame direction="row">
        <frame width="50%">
          <p>Department: {{ employee.department }}</p>
          <p>Start date: {{ employee.start_date }}</p>
        </frame>
        <frame width="50%">
          <img show-if="employee.photo" src="{{ employee.photo }}" max-height="150pt" />
        </frame>
      </frame>
    </page>
  </repeat>
</document>

This generates one page per employee -- useful for directories, ID cards, certificates, or property listings.

Repeating with Outline Tracking

When building a table of contents, use <repeat outline="..."> to iterate over collected outline entries:

xml
<repeat outline="sections" item="entry">
  <tr>
    <td>{{ entry.page-number }}</td>
    <td>{{ entry.text-content }}</td>
  </tr>
</repeat>

Repeating over the outline requires being in a deferred page or a deferred flow. See the Table of Contents guide for full details.