Templating & data
Use real Python inside {% %} tags, and reference JSON/YAML/CSV data as data.file.property.
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:
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():
{%
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.<stem>:
- 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.
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:
{%
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; 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. |
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:
{% 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:
## 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:
---
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
for the full table and a live demo of each.