Skip to content

Layout and Sizing

Frames are the fundamental building block of layout in Press. Every page is itself a frame, and you nest frames within frames to create any layout you can imagine. This guide covers how frames work, how to size them, and how to position content precisely.

The <frame> Element

A <frame> is a rectangular container that holds other elements.

xml
<frame>
  <h2>Section Title</h2>
  <p>Some content goes here.</p>
</frame>

By default, a frame stacks its children vertically from top to bottom.

Direction: Column vs. Row

The direction attribute controls how children are arranged within a frame.

Column Direction (Default)

direction="column" (or direction="col") stacks children vertically. This is the default, so you can omit it.

xml
<frame direction="column">
  <p>First paragraph (top)</p>
  <p>Second paragraph (middle)</p>
  <p>Third paragraph (bottom)</p>
</frame>

Row Direction

direction="row" arranges children horizontally from left to right.

xml
<frame direction="row">
  <frame width="50%">
    <p>Left column</p>
  </frame>
  <frame width="50%">
    <p>Right column</p>
  </frame>
</frame>

Width and Height

Frame dimensions can be specified using several value types.

Static Values

Use points (pt) or centimetres (cm) for exact dimensions. PDFs have 72 points per inch.

xml
<frame width="200pt" height="100pt">
  <p>Exactly 200pt wide and 100pt tall.</p>
</frame>

<frame width="10cm" height="5cm">
  <p>Exactly 10cm wide and 5cm tall.</p>
</frame>

Parent-Relative (Percentage)

A percentage value sizes the frame relative to its parent.

xml
<frame direction="row">
  <frame width="70%">
    <p>This takes 70% of the parent's width.</p>
  </frame>
  <frame width="30%">
    <p>This takes the remaining 30%.</p>
  </frame>
</frame>

Fill

fill causes the frame to take up all remaining space left by its siblings. This is useful when you want one element to be a fixed size and another to fill the rest.

xml
<frame direction="row" height="100%">
  <frame width="200pt">
    <p>Fixed sidebar (200pt wide).</p>
  </frame>
  <frame width="fill">
    <p>Main content fills the remaining width.</p>
  </frame>
</frame>

Auto Sizing

If you do not specify a width or height, the frame sizes itself automatically to fully contain its content. A frame will grow as large as needed, but never larger than its parent.

xml
<frame>
  <p>This frame will be exactly as tall as the paragraph requires.</p>
</frame>

Min/Max Constraints

You can constrain dimensions with min-width, max-width, min-height, and max-height. These accept the same value types as width and height: points, cm, or percentages.

xml
<frame min-width="200pt" max-width="80%" min-height="50pt">
  <p>This frame is at least 200pt wide but no more than 80% of its
    parent. It is at least 50pt tall.</p>
</frame>

This is particularly useful for responsive-feeling layouts where content length varies:

xml
<frame direction="row">
  <frame width="fill" min-width="150pt" max-width="300pt">
    <p>Sidebar content</p>
  </frame>
  <frame width="fill">
    <p>Main content</p>
  </frame>
</frame>

Absolute Positioning

By default, frames are positioned relative to their siblings -- each one follows the previous. You can override this with absolute positioning using top, left, right, and bottom. These offsets are measured from the parent frame's edges.

xml
<frame width="100%" height="100%">
  <!-- This frame is pinned to the top-right corner of its parent -->
  <frame top="0pt" right="0pt" width="80pt" height="30pt">
    <p font-size="8pt">Page 1</p>
  </frame>

  <!-- This frame is pinned to the bottom-left -->
  <frame bottom="10pt" left="10pt">
    <p font-size="8pt">Confidential</p>
  </frame>

  <!-- Normal flow content is unaffected by absolutely positioned frames -->
  <h1>Report Title</h1>
  <p>Body content goes here.</p>
</frame>

When any of top, left, right, or bottom is set, the frame becomes absolutely positioned. It no longer participates in the normal flow, meaning it will not push its siblings around and its siblings will not push it.

Alignment

h-align -- Horizontal Alignment

Controls where child blocks are positioned horizontally within a frame. Values: left (default), right, center.

xml
<frame h-align="center" width="100%">
  <frame width="200pt" background-color="#eeeeee" padding="12pt">
    <p>This 200pt-wide box is centred in its parent.</p>
  </frame>
</frame>

v-align -- Vertical Alignment

Controls where child blocks are positioned vertically within a frame. Values: top (default), bottom, center.

xml
<frame v-align="center" width="100%" height="100%">
  <p>This text is vertically centred.</p>
</frame>

Combining Alignment

Use both to centre content in two dimensions:

xml
<frame v-align="center" h-align="center" width="100%" height="100%">
  <h1 text-align="center">Centred Title</h1>
  <p text-align="center">Both vertically and horizontally centred.</p>
</frame>

Note the distinction: h-align and v-align position block-level children within a frame. text-align controls the alignment of inline content (text) within a block. This allows precise control of text blocks. For instance, we can center align the block and right align the text:

xml
<frame v-align="center" h-align="center" width="100%" height="100%">
  <frame width="100pt" text-align="right">Both vertically and horizontally centred but right aligned text.</frame>
</frame>

Padding

Padding adds space inside the frame, between its edges and its content.

xml
<!-- Uniform padding -->
<frame padding="12pt">
  <p>12pt of space on all sides.</p>
</frame>

<!-- Per-side padding -->
<frame padding-top="24pt" padding-bottom="12pt"
       padding-left="16pt" padding-right="16pt">
  <p>Different padding on each side.</p>
</frame>

When you set width or height on a frame, those dimensions include borders and padding.

Background Color

Apply a solid background to any frame using background-color.

xml
<frame background-color="#2c3e50" padding="16pt">
  <p font-color="#ffffff">White text on a dark background.</p>
</frame>

This works with any supported color format -- hex, rgb, rgba, hsl, or named colors.

Border Radius

The border-radius attribute rounds the corners of a frame's background and border.

xml
<frame background-color="#3498db" padding="16pt" border-radius="8pt">
  <p font-color="white">Rounded corners at 8pt radius.</p>
</frame>

Borders

Use border-weight and border-color to add borders. Like padding and margin, these can be set per side.

xml
<!-- Full border -->
<frame border-weight="1pt" border-color="#cccccc" padding="12pt">
  <p>Bordered frame.</p>
</frame>

<!-- Bottom border only (like a divider) -->
<frame border-weight-bottom="2pt" border-color-bottom="#333333"
       padding-bottom="8pt" margin-bottom="8pt">
  <h2>Section Title</h2>
</frame>

Spacing Between Siblings

The space-before-desired and space-after-desired attributes control the gap between a frame and its preceding or following sibling. Spacing is not applied if there is no sibling in the direction specified.

xml
<h2 space-after-desired="6pt">Findings</h2>
<p space-before-desired="6pt" space-after-desired="12pt">
  The analysis revealed three primary trends...
</p>
<p space-before-desired="12pt">
  Additionally, the data suggests...
</p>

You can set these globally in <styles> to apply consistent spacing throughout the document:

xml
<styles>
  <h2>
    <space-before-desired>18pt</space-before-desired>
    <space-after-desired>8pt</space-after-desired>
  </h2>
  <p>
    <space-before-desired>6pt</space-before-desired>
  </p>
</styles>

Nesting Frames for Complex Layouts

The real power of frames comes from nesting. You combine direction="row" and direction="column" frames to build any layout.

Example: Two-Column Layout

xml
<press>
  <document format="A4" page-margin="2cm">
    <page>
      <h1>Research Summary</h1>
      <frame direction="row" width="100%">
        <frame width="48%">
          <h3>Methodology</h3>
          <p>We surveyed 500 participants across three regions
            using a standardised questionnaire.</p>
        </frame>
        <frame width="4%" />
        <frame width="48%">
          <h3>Key Findings</h3>
          <p>Response rates exceeded 85% in all regions, with
            the highest participation in the northern district.</p>
        </frame>
      </frame>
    </page>
  </document>
</press>

Example: Sidebar and Main Content

xml
<press>
  <document format="A4" page-margin="1.5cm">
    <page>
      <frame direction="row" width="100%" height="100%">
        <!-- Sidebar -->
        <frame width="30%" background-color="#f5f5f5" padding="12pt">
          <h3 font-size="11pt">Contents</h3>
          <p font-size="9pt">1. Overview</p>
          <p font-size="9pt">2. Methodology</p>
          <p font-size="9pt">3. Results</p>
          <p font-size="9pt">4. Conclusion</p>
        </frame>

        <!-- Main content -->
        <frame width="70%" padding-left="16pt">
          <h1>Annual Sustainability Report</h1>
          <p>Oakridge Environmental Services has committed to
            reducing carbon emissions by 40% over the next decade.</p>
          <h2>Overview</h2>
          <p>This report details our progress towards the
            targets set in the 2024 sustainability framework.</p>
        </frame>
      </frame>
    </page>
  </document>
</press>

Example: Centred Card

xml
<press>
  <document format="A4" page-margin="2cm">
    <page>
      <frame v-align="center" h-align="center" width="100%" height="100%">
        <frame width="70%" background-color="#ffffff"
               border-weight="1pt" border-color="#dddddd"
               border-radius="6pt" padding="24pt">
          <h2 text-align="center">Invitation</h2>
          <p text-align="center">You are cordially invited to the annual
            meeting of Whitfield & Partners.</p>
          <p text-align="center" font-color="#888888" font-size="10pt">
            14 March 2026 | Thornton Conference Centre
          </p>
        </frame>
      </frame>
    </page>
  </document>
</press>
xml
<press>
  <document format="A4" page-margin="0cm">
    <page>
      <!-- Header bar -->
      <frame direction="row" width="100%" height="4cm" background-color="#1a1a2e" padding="1.5cm" v-align="center">
        <frame width="fill">
          <p font-color="white" font-size="16pt">Crestwood Logistics</p>
        </frame>
        <frame>
          <p font-color="#aaaaaa" font-size="10pt" text-align="right">
            Delivery Confirmation
          </p>
        </frame>
      </frame>

      <!-- Body content with its own padding -->
      <frame padding="1.5cm">
        <h2>Shipment #48291</h2>
        <p>Dispatched: 7 February 2026</p>
        <p>Destination: 42 Elmsworth Road, Kingsbridge</p>
        <table>
          <tr>
            <th>Item</th>
            <th>Quantity</th>
            <th>Weight</th>
          </tr>
          <tr>
            <td>Flat-pack furniture set</td>
            <td>2</td>
            <td>34.5 kg</td>
          </tr>
          <tr>
            <td>Kitchen appliance box</td>
            <td>1</td>
            <td>12.2 kg</td>
          </tr>
        </table>
      </frame>
    </page>
  </document>
</press>

Summary of Frame Attributes

AttributeValuesDescription
directioncolumn (default), rowStack children vertically or horizontally
width / heightpt, cm, %, fill, autoDimensions of the frame
min-width / max-widthpt, cm, %Constrain width
min-height / max-heightpt, cm, %Constrain height
top / left / right / bottompt, cmAbsolute positioning offsets
h-alignleft, right, centerHorizontal alignment of children
v-aligntop, bottom, centerVertical alignment of children
paddingpt, cmInner spacing (also per-side)
marginpt, cmOuter spacing (also per-side)
background-colorAny color valueBackground fill
border-radiuspt, cmRounded corners
border-weightpt (also per-side)Border thickness
border-colorAny color value (also per-side)Border color
space-before-desiredpt, cmDesired gap before this element
space-after-desiredpt, cmDesired gap after this element