---
title: "Layouts and Partials · RUAL Documentation"
description: "Store a template once and reuse it: partials for shared pieces, layouts that wrap the page, and the variables every template can read."
canonical: https://docs.rual.nl/web/layouts-and-partials
language: en
---

# Layouts and Partials

Store a template once with the type `web` and a name. `{{> name}}` prints it inside another template, the `layout` pin wraps a page in it, and saving it takes effect everywhere at once.

In short

- Stored templates live in the templates store, the same place mail templates live.

- A partial is used inside another template. A layout wraps the page and prints it with `{{{body}}}` and the head tags with `{{{head}}}`.

- A page and its actions that use the same stored row can never drift apart.

## A stored template has a type and a name

Create it through the [cluster API](https://docs.rual.nl/cluster/api-guide). Your token needs the `blueprinttemplates create` scope.

```
{
  "type": "web",
  "name": "product-card",
  "html": "<li>{{name}}: {{price | money \"EUR\"}}</li>"
}
```

A template also has a `stylesheet` and a `script` field. Once it exists it shows up in **Manage Templates** in [RUAL Studio](https://docs.rual.nl/interfaces/rual-studio#user-interfaces), where you can edit its HTML, its stylesheet and its script.

> **Creating one from Studio** The create dialog in **Manage Templates** has no web type yet. A name no web template has is also looked up among all other templates, so an **Email Template** you create there and give the same name works as a partial or a layout, too. Replace its starting HTML with your own.

## A partial is a shared piece

Print it with `{{> name}}`. It sees the data around it, or the value you hand it:

```
{{> site-header}}

<ul>
  {{for p in products}}
    {{> product-card p}}
  {{/for}}
</ul>
```

- **Where it may stand:** only where text goes, and it must end there too. Inside a tag, an attribute or a ` ` it does not compile, because a partial is compiled on its own and could not be escaped for the place it lands in.

- **A name that does not exist** fails the render with a message naming it. The visitor reads that the page failed, and a blueprint developer reads why.

- **A partial that includes itself** fails at 48 levels deep with a message.

- **Only a layout's stylesheet and script are linked.** Those fields of a partial are not, so put a partial's styles in the layout or the page.

For a small template used in one place only, keep it in the template itself:

```
{{define "badge"}}<span class="badge">{{.}}</span>{{/define}}

<h1>{{title}} {{> badge status}}</h1>
```

## A layout wraps the page

Set the `layout` pin of [`web_render`](https://docs.rual.nl/block-types/web/web_render) to the template's name or GUID. The block's `template_guid` setting does the same when the pin is empty.

```
<!doctype html>
<html lang="{{language}}">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="{{viewport}}">
  {{{head}}}
</head>
<body>
  {{> site-header}}
  {{{body}}}
  {{> site-footer}}
</body>
</html>
```

- `{{{body}}}` is the page, rendered first. `{{{head}}}` is where the generated [head tags](https://docs.rual.nl/web/seo) go. Without it they go right before ` `.

- The layout sees the same data as the page: `data`, the custom pins, `title`, `nonce` and the rest.

- The layout's own stylesheet and script are linked automatically, after the other head tags.

- A name is looked up among web templates first and then among all others, so a mail layout can be a page's layout too.

## Three ways a page gets its document

| The render block has | The document is |
| --- | --- |
| A layout | The layout, with the page in `{{{body}}}`. |
| No layout, and a template that starts with `<!doctype` or `<html` | Your template, whole. |
| No layout, and any other template | A plain HTML5 document around your template, with `lang`, charset and viewport set. |

The head tags are written in all three. They go where `{{{head}}}` stands, else before ` `, else right after ` `. A tag your head already has [is not written twice](https://docs.rual.nl/web/seo#your-own-tags).

## Every template can read the same variables

| Template | Sees |
| --- | --- |
| The page and its layout | `data` fields, custom pins, `web`, plus `title`, `description`, `nonce`, `language`, `viewport` and `head`. A layout also has `body`. |
| A [`web_template`](https://docs.rual.nl/block-types/web/web_template) | `data` fields, custom pins and `web`. |
| A row of [`web_foreach`](https://docs.rual.nl/block-types/web/web_foreach) | The item's fields first, then `data` fields, custom pins and `web`. |
| A partial | What the template around it sees, with the given value in front when you hand it one. |

[Template Syntax](https://docs.rual.nl/web/templates#variables) lists each variable.

## Saving takes effect everywhere

Saving a template takes effect on every node at once. A template is compiled once per version of its text, so a new version never reuses an old compile. A brand new name is found within seconds: a name nobody has created is remembered as missing for 5 seconds, then looked for again.

## Store what more than one flow renders

#### Store it

The header, the footer, a product card, a table row. The page's [`web_foreach`](https://docs.rual.nl/block-types/web/web_foreach) and the action's [`web_template`](https://docs.rual.nl/block-types/web/web_template) both say `{{> order-row}}`, so an edited row looks the same as a loaded one.

#### Copy it

The same row typed into the list block and into the action's render block. The first change you make to one of them is a bug the visitor sees only after they edit something.

## Next steps

- [Lists and Tables](https://docs.rual.nl/web/lists): Rows from a stored template, each with its own key.

- [SEO and Sharing](https://docs.rual.nl/web/seo): What goes into the head of every page.

- [Email System](https://docs.rual.nl/tutorials/email-system): Mail templates: the same template store and syntax, used for email.
