> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tipar.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Layout

> Arrange content vertically with column, horizontally with row, and add space with spacer.

Three nodes do all the arranging: **`column`** stacks things vertically, **`row`** places them side by side, and **`spacer`** adds a gap. Everything else (`text`, `table`, `image`) is content you drop into them.

## column

A vertical stack. Children render top to bottom, with an optional uniform gap between them.

```json theme={"dark"}
{
  "type": "column",
  "spacing": 8,
  "items": [
    { "type": "text", "value": "Bill to", "style": { "color": "grey.darken1" } },
    { "type": "text", "value": "{{customer.name}}", "style": { "bold": true } },
    { "type": "text", "value": "{{customer.address}}" }
  ]
}
```

| Field     | Type            | Required | Notes                                        |
| --------- | --------------- | -------- | -------------------------------------------- |
| `items`   | Node\[]         | **yes**  | The children, in order.                      |
| `spacing` | number (points) | no       | Gap between successive items. Omit for none. |

`column` is the workhorse — most page bodies are a `column` with `spacing` and a handful of items.

## row

A horizontal band split into sized cells. Each item has a `size` and a `child`.

```json theme={"dark"}
{
  "type": "row",
  "items": [
    { "size": { "kind": "relative", "weight": 1 }, "child": { "type": "text", "value": "{{company.name}}", "style": { "bold": true } } },
    { "size": { "kind": "constant", "width": 180 }, "child": { "type": "text", "value": "INVOICE", "align": "right" } }
  ]
}
```

Each `items[]` entry has:

| Field   | Type          | Required | Notes                              |
| ------- | ------------- | -------- | ---------------------------------- |
| `size`  | sizing object | **yes**  | How wide this cell is — see below. |
| `child` | Node          | **yes**  | What goes in the cell.             |

### Sizing a cell

A cell's `size` is one of two kinds:

<Tabs>
  <Tab title="relative">
    ```json theme={"dark"}
    { "kind": "relative", "weight": 2 }
    ```

    The cell takes a share of the **remaining** width, proportional to its `weight`. Two cells with weights `1` and `2` split the row one-third / two-thirds. Use relative sizing for content that should flex with the page.
  </Tab>

  <Tab title="constant">
    ```json theme={"dark"}
    { "kind": "constant", "width": 180 }
    ```

    The cell is exactly `width` points wide, regardless of page size. Use it for fixed columns — a date block, a logo lane, a totals strip. Relative cells then share whatever width is left.
  </Tab>
</Tabs>

<Tip>
  Mixing the two is the common case: a `constant` cell for the thing that must be a fixed width, and a `relative` cell with `weight: 1` next to it to soak up the rest.
</Tip>

A two-column body — bill-to on the left, pay-to on the right — is just a `row` of two `relative` cells, each holding a `column`:

```json theme={"dark"}
{
  "type": "row",
  "items": [
    { "size": { "kind": "relative", "weight": 1 }, "child": { "type": "column", "items": [
      { "type": "text", "value": "Bill to", "style": { "color": "grey.darken1" } },
      { "type": "text", "value": "{{billTo.name}}", "style": { "bold": true } }
    ] } },
    { "size": { "kind": "relative", "weight": 1 }, "child": { "type": "column", "items": [
      { "type": "text", "value": "Pay to", "style": { "color": "grey.darken1" }, "align": "right" },
      { "type": "text", "value": "{{payTo.name}}", "style": { "bold": true }, "align": "right" }
    ] } }
  ]
}
```

## spacer

A fixed vertical gap. Useful inside a `column` when you want more (or less) space than uniform `spacing` gives, or to push content down a page — certificates lean on it heavily.

```json theme={"dark"}
{ "type": "spacer", "size": 24 }
```

| Field  | Type            | Required | Notes                           |
| ------ | --------------- | -------- | ------------------------------- |
| `size` | number (points) | **yes**  | Height of the gap. Must be ≥ 0. |

<Note>
  For horizontal space between `row` cells, don't use a spacer — adjust the cell `size`/`weight` instead, or add `padding` if it's a [table](/templates/tables) cell.
</Note>

## Putting it together

Layout nodes nest without limit. A typical page body is a `column` whose items are some `row`s, a `table`, and a few `spacer`s:

```json theme={"dark"}
{
  "type": "column",
  "spacing": 14,
  "items": [
    { "type": "row", "items": [ "...header band..." ] },
    { "type": "table", "...": "..." },
    { "type": "spacer", "size": 8 },
    { "type": "text", "value": "Total due: {{invoice.total}}", "style": { "bold": true }, "align": "right" }
  ]
}
```

<Card title="Next: Text & styling" icon="font" href="/templates/text">
  Style the text you place into these layouts.
</Card>
