Skip to Content

Tables

Tables let you display structured data in rows and columns — invoice line items, product lists, order summaries, and anything that follows a repeating pattern.

Creating a table

Add a table the same way you add any component: select a section in the Layers panel, click + New Element, and choose Table. A default table with 2 columns and 2 rows appears inside the section.

Table structure

Every table has two parts:

  • Header row — The top row, where you put column labels like “Description”, “Qty”, “Price”.
  • Data rows — The rows below, where you put your content or variables.

The header row is visually distinct by default so readers can tell it apart from the data.

Adding and removing columns

When you select the table, a green + button appears on the right edge — click it to add a column. A red × button appears above each column to delete it.

To resize a column, hover between two column headers until you see the resize handle, then drag left or right. The adjacent column adjusts to compensate, so the total table width stays the same.

Adding and removing rows

A green + button at the bottom edge adds a new row. A red × button beside each row removes it.

To resize a row, hover between two rows and drag. Unlike columns, each row height is independent.

Editing cells

Double-click a cell to edit its content. You can type static text like “Description” for a header, or use variables like {{items.description}} for dynamic data.

Click outside the cell when you’re done editing.

Dynamic tables

This is the most powerful feature of tables. When you use array variables in a data row, the table automatically generates one row per item in your data.

For example, set up your data row with:

| {{items.description}} | {{items.qty}} | {{items.unit_price}} |

Then pass this data through the API:

{ "items": [ { "description": "Widget A", "qty": 2, "unit_price": 15.00 }, { "description": "Widget B", "qty": 5, "unit_price": 8.50 }, { "description": "Widget C", "qty": 1, "unit_price": 42.00 } ] }

The table will render three rows, one for each item. You don’t need to define the number of rows in advance — the table grows with your data.

You can also use expressions in table cells. For example, {{items.qty * items.unit_price}} computes the line total for each row.

Tables and page breaks

When a dynamic table has more rows than fit on one page, it automatically breaks across pages. The header row is repeated at the top of each new page so readers always know which column is which.

For page breaks to work correctly, the table must be the only element inside its section. If you need other elements above or below the table, put them in separate sections.

Styling cells

Select the table to access styling options in the right panel. You can switch between two modes:

  • All Cells — Apply the same style to every cell at once. Use this for a consistent baseline look.
  • Individual Cell — Click a specific cell and style just that one. Use this for the header row or to highlight specific cells.

Available styling options:

  • Typography — Font, size, weight, color, alignment
  • Fill — Background color
  • Border — Width, style, color on each side
  • Padding — Inner spacing between the cell edge and the text

A few practical tips for styling:

  • Give the header row a bold font or a subtle background color to make it stand out
  • Right-align numbers (quantities, prices, totals) for easier reading
  • Add enough padding so text doesn’t crowd the cell edges — 4 to 8 pixels is usually enough

Next steps

  • Styling — Full styling reference for all components
  • Expressions — Computed values and aggregates like {{sumproduct(items.qty, items.price)}}
  • Data Binding — How to pass data to your templates via the API
Last updated on