Skip to content

Tables

Tables in Press use familiar HTML-like syntax. This guide covers everything from basic structure to data-driven tables, styling, and advanced features like column spanning and rotation.

Basic Structure

xml
<table>
  <tr>
    <th>Region</th>
    <th>Revenue</th>
    <th>Growth</th>
  </tr>
  <tr>
    <td>North</td>
    <td>£1.2M</td>
    <td>+12%</td>
  </tr>
  <tr>
    <td>South</td>
    <td>£980K</td>
    <td>+8%</td>
  </tr>
</table>

The standard tags <tr>, <td>, and <th> are components from Press's standard library. The underlying primitives are table, row, and cell.

Column Widths

Set widths on cells in the first row to control column proportions:

xml
<table>
  <tr>
    <th width="50%">Description</th>
    <th width="20%">Quantity</th>
    <th width="30%">Price</th>
  </tr>
  ...
</table>

Width values can be percentages, fixed sizes (100pt), or fill for remaining space.

Column Spanning

Use colspan to span a cell across multiple columns:

xml
<tr>
  <td colspan="2" font-style="bold" text-align="right">Subtotal:</td>
  <td text-align="right">£2,180</td>
</tr>

Styling Tables

Inline Styles on Cells

xml
<tr>
  <th background-color="#1e3a5f" font-color="white" padding="10pt">Region</th>
  <th background-color="#1e3a5f" font-color="white" padding="10pt">Revenue</th>
</tr>

Global Table Styles

Using <styles> with <child> rules is far cleaner for consistent table styling:

xml
<styles>
  <table>
    <width>fill</width>
    <child name="th">
      <background-color>#1e3a5f</background-color>
      <font-color>white</font-color>
      <font-style>bold</font-style>
      <font-size>9pt</font-size>
      <padding>10pt</padding>
      <border-weight>0</border-weight>
    </child>
    <child name="td">
      <border-weight>0</border-weight>
      <border-weight-bottom>0.5pt</border-weight-bottom>
      <border-color>#e5e7eb</border-color>
      <padding-left>10pt</padding-left>
      <padding-right>10pt</padding-right>
      <padding-top>8pt</padding-top>
      <padding-bottom>8pt</padding-bottom>
      <v-align>center</v-align>
    </child>
  </table>
</styles>

Style Aliases for Table Variants

Create different table styles and apply them by name:

xml
<styles>
  <alias name="borderless">
    <child name="td">
      <border-weight>0</border-weight>
      <padding>4pt</padding>
    </child>
  </alias>

  <alias name="summary-row">
    <child name="td">
      <border-weight>0</border-weight>
      <padding-top>16pt</padding-top>
      <padding-bottom>16pt</padding-bottom>
    </child>
  </alias>
</styles>
xml
<table style="@borderless">...</table>

<tr style="@summary-row">
  <td colspan="2" font-style="bold" text-align="right">Grand Total:</td>
  <td text-align="right">£4,500</td>
</tr>

Cell Alignment

AttributeApplies toValues
text-alignText within cellleft, right, center, justified
h-alignCell content blockleft, center, right
v-alignCell content blocktop, center, bottom
xml
<td text-align="right" v-align="center">£1,200</td>

Border Properties

Table borders automatically collapse to avoid duplicate borders rendering between cells. Here are properties for controlling borders:

AttributeDescription
border-weightAll borders
border-weight-topTop border only
border-weight-bottomBottom border only
border-weight-leftLeft border only
border-weight-rightRight border only
border-colorColor of all borders
border-color-topColor of top border
border-color-bottomColor of bottom border
border-color-leftColor of left border
border-color-rightColor of right border
xml
<td border-weight="0" border-weight-bottom="1pt" border-color="#d1d5db">
  Content with only a bottom border
</td>

Data-Driven Tables

Generate rows from data with <repeat>:

xml
<table>
  <tr font-size="9pt">
    <th width="45%">Description</th>
    <th text-align="center">Price</th>
    <th text-align="center">Qty</th>
    <th text-align="right">Total</th>
  </tr>
  <repeat data="data.items" item="line">
    <tr font-size="8pt">
      <td>
        <frame font-size="9pt">{{ line.name }}</frame>
        <frame show-if="line.description" font-size="8pt" font-color="#6b7280">
          {{ line.description }}
        </frame>
      </td>
      <td h-align="center">£{{ line.price }}</td>
      <td h-align="center" text-align="center">{{ line.quantity }}</td>
      <td h-align="right">£{{ line.total }}</td>
    </tr>
  </repeat>
</table>

Tables Across Pages

Tables inside flows automatically break across pages. Each row is treated as a breakable unit -- Press will move the new row onto a new page or into a new frame.

To stop a table from breaking:

xml
<table break="never">
  <tr background-color="#1e3a5f" font-color="white">
    <td width="65%" font-style="bold" text-align="right" colspan="2">
      Subtotal:<br />Tax (20%):
    </td>
    <td h-align="right">
      £1,800<br />£360
    </td>
  </tr>
  <tr background-color="#0f172a" font-color="white" font-size="12pt">
    <td font-style="bold">Payment: Bank Transfer</td>
    <td font-style="bold" text-align="right">Grand Total:</td>
    <td h-align="right" font-style="bold">£2,160</td>
  </tr>
</table>

Rotated Tables

For wide data tables that don't fit in portrait, rotate the frame 270 degrees:

xml
<frame rotation="270" height="100%">
  <table>
    <tr>
      <th>Variable</th>
      <th>Jan</th>
      <th>Feb</th>
      <th>Mar</th>
      <th>Apr</th>
      <th>May</th>
      <th>Jun</th>
      <th>Jul</th>
      <th>Aug</th>
      <th>Sep</th>
      <th>Oct</th>
      <th>Nov</th>
      <th>Dec</th>
    </tr>
    <repeat data="data.monthly-stats" item="row">
      <tr font-size="7pt">
        <td font-style="bold">{{ row.variable }}</td>
        <repeat data="row.values" item="val">
          <td text-align="center">{{ val }}</td>
        </repeat>
      </tr>
    </repeat>
  </table>
</frame>

Note: width and height on rotated elements refer to pre-rotation dimensions. In the example above, the table is given the full height of the frame as width to render. See the Transformations guide for details.