# Templating & data Logic in aardvark pages is **real Python**, written inside `{% %}` tags. ## The two kinds of block A block that is a **single expression** is evaluated and its result is printed: ```aardvark Today's answer is {% 6 * 7 %}. ``` A block that is one or more **statements** runs via `exec`; it writes to the page with `page.print(...)` — the write-mirror of `page.get()`: ```aardvark {% for fruit in ["apples", "pears", "plums"]: page.print("- ", fruit, "\n") %} ``` All blocks on a page share one namespace, so a variable set early is available later. ## Data files Drop `.json`, `.yaml`, or `.csv` files in `data/`. Each becomes `data.`: - A JSON/YAML object is reachable as `data.file.property`. - A CSV becomes a **list of row objects** keyed by the header row. This site ships `data/products.yaml`. Here it is, live: > There are **3** products. The first is > **Sticker Pack** at $8. A loop over the same data: - Sticker Pack ($8) - Enamel Mug ($18) - Zip Hoodie ($55) The Markdown for that loop was: ```aardvark {% for p in data.products.items: page.print(f'- {p.name} (${p.price})\n') %} ``` ## What's in scope | Name | What it is | | --- | --- | | `data` | Your `data/` files (`data.file.prop`) | | `site` | `site:` block from `aardvark.config.yaml` | | `config` | The full configuration object | | `page` | This page's front matter — `page.get(key, default)` reads it; `page.print(*strings)` writes to the page | | `component(name, **props)` | Embed a React island. `component('library', 'Name', …)` reaches a [theme component library](/components/extras/component-libraries/); `component('aardvark', 'tag', …)` reaches a built-in by its tag name (e.g. `component('aardvark', 'card', …)`) so you can build one in a `for` loop. See [Components](/authoring/components-and-snippets/). | | `snippet(name, **props)` | Alias of `component` for your `snippets/` | | `asset(path)` | Return the build's fingerprinted URL for a static asset. Use it when constructing URLs dynamically; literal asset URLs are rewritten automatically. | | `components` | Sorted list of every registered component name | | `print(*args)` | Lower-level page output (always available; the only form inside custom-component bodies, where `page` isn't in scope) | ## Showing literal syntax To display `{% %}` without running it, wrap it: ```aardvark {% raw %} this {% will_not_run() %} is shown verbatim {‍% endraw %} ``` ## Headings and anchor links Every heading (levels 1–4) gets a stable `id` and a permalink. Hover a heading and a link icon fades in to its right — click it to jump to that section and put the anchor in your address bar to share. The `id` defaults to a GitHub-style slug of the heading text (`## Heading anchors` → `#headings-and-anchor-links`), and repeated headings are de-duplicated (`#setup`, `#setup-1`, …). To pin a short, stable anchor yourself, add `{#custom-id}` at the end of the heading line: ```markdown ## Configuration options {#config} ``` links as `#config` (the `{#…}` marker is removed from the rendered heading). Custom ids keep working even if you later reword the heading, so existing links don't break. ## Page layout modes A page's `mode` front matter controls its layout — toggling the left nav, the right-hand TOC, and the content width: ```yaml --- title: Release dashboard mode: wide --- ``` The options are `wide`, `full`, `toc-only`, and `uncapped` (omit `mode`, or use `default`, for the standard nav-plus-TOC layout). See **[Layout modes](/modes/)** for the full table and a live demo of each.