Documentation
Writing and customizing templates
Everlock uses Tera as its template engine. Tera's syntax is similar to Jinja2 and Django templates. Templates live in the layouts/ directory of your site repository. This page explains the syntax, the context variables available in each template, and common customization patterns.
Template syntax basics
Output a variable
<h1>{{ page.title }}</h1>
Double braces output the value of a variable. Any HTML in the value is escaped by default.
Output raw HTML safely
<div class="content"> {{ page.content | safe }} </div>
The | safe filter tells Tera the value is already trusted HTML and should not be escaped. Use this for rendered Markdown content.
Conditionals
{% if page.git_date %} <p class="meta">Updated {{ page.git_date }}</p> {% endif %}
{% if page.tags %} <ul> {% for tag in page.tags %} <li><a href="/tags/{{ tag }}">{{ tag }}</a></li> {% endfor %} </ul> {% endif %}
Loops
{% for link in site.nav.links %} <a href="{{ link.url }}">{{ link.label }}</a> {% endfor %}
Default values
<time>{{ p.git_date | default(value=p.date) | default(value="") }}</time>
Filters chain left to right. | default(value=x) substitutes x when the left side is empty or undefined.
String filters
{{ page.title | upper }} {{ tag | replace(from="-", to=" ") | title }}
Common Tera filters: upper, lower, title, trim, replace, truncate, length, first, last.
Date helpers
Everlock adds a small date layer on top of Tera for Markdown sites:
<p>Now: {{ now() }}</p> <p>Today: {{ today() }}</p> {% if page.date is before(date=now()) %} <p>This page date is in the past.</p> {% endif %} <time>{{ page.date | date_format(format="%Y-%m-%d") }}</time>
Accepted input formats:
YYYY-MM-DD- RFC3339 timestamps such as
2026-06-11T08:30:00Z
today() and date-only comparisons use the site timezone from site.toml. If
no timezone is set, Everlock falls back to UTC.
Template inheritance
Every template in Everlock extends base.html. The pattern uses {% extends %} and {% block %}:
layouts/base.html defines named blocks:
<!doctype html> <html> <head> <title>{% block title %}{{ page.title }} | {{ site.title }}{% endblock %}</title> </head> <body> <nav> {% for link in site.nav.links %} <a href="{{ link.url }}">{{ link.label }}</a> {% endfor %} </nav> <main> {% block main %}{% endblock %} </main> </body> </html>
layouts/single.html fills in the block:
{% extends "base.html" %} {% block main %} <article> <h1>{{ page.title }}</h1> <div class="content">{{ page.content | safe }}</div> </article> {% endblock %}
Any block not overridden in the child template renders from the parent. A child can call {{ super() }} to include the parent block's content and then add to it.
Context variables reference
Available in all templates
| Variable | Type | Content |
|---|---|---|
site.title | string | Site title from site.toml |
site.description | string | Site description from site.toml |
site.base_url | string | Base URL from site.toml |
site.timezone | string | Optional site timezone used by today() and date formatting |
site.nav.links | list | Navigation links, each with .label and .url |
data | map | All .toml files from the data/ directory |
In single.html (content pages)
| Variable | Type | Content |
|---|---|---|
page.title | string | Title from frontmatter |
page.content | string | Rendered HTML of the page body |
page.summary | string | HTML of content before <!--more-->, or empty |
page.tags | list | Tag strings |
page.date | string | Frontmatter date |
page.git_date | string | Date of the last git commit for this file |
page.url | string | Page URL path, e.g. /docs/reference |
page.extra | map | Scalar extra frontmatter fields |
page.related | list | Up to 5 related pages (by shared tags), each with .title, .url, .tags |
page.prev_page | object | Previous page in a series, with .title and .url |
page.next_page | object | Next page in a series, with .title and .url |
page.uses_mermaid | bool | Whether the page contains a Mermaid diagram |
In list.html and custom section templates
| Variable | Type | Content |
|---|---|---|
page.title | string | Section title from _index.md or URL path |
page.content | string | Rendered HTML from _index.md body |
pages | list | Child pages, each with .title, .url, .snippet, .tags, .date, .git_date |
pagination | object | Pagination state (only when paginate_by is set in site.toml) |
pagination.current_page | int | Current page number |
pagination.total_pages | int | Total number of pages |
pagination.has_prev | bool | Whether a previous page exists |
pagination.has_next | bool | Whether a next page exists |
pagination.prev_url | string | URL of the previous page |
pagination.next_url | string | URL of the next page |
Example: customizing base.html
Here is a base.html that adds a sticky header with a brand logo, a search link, and a footer:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block title %}{{ page.title }} | {{ site.title }}{% endblock %}</title> <link rel="stylesheet" href="/assets/style.css"> <link rel="alternate" type="application/rss+xml" href="/index.xml" title="{{ site.title }} RSS"> </head> <body> <header class="site-header"> <a class="brand" href="/">{{ site.title }}</a> <nav> {% for link in site.nav.links %} <a href="{{ link.url }}">{{ link.label }}</a> {% endfor %} <a href="/search">Search</a> </nav> </header> <main> {% block main %}{% endblock %} </main> <footer> <p>{{ site.title }} · <a href="/index.xml">RSS</a></p> </footer> </body> </html>
Example: a content page with related links
layouts/single.html showing the page, its tags, and related pages in a sidebar:
{% extends "base.html" %} {% block main %} <div class="page-layout"> <article class="page-content"> <header> <h1>{{ page.title }}</h1> {% if page.git_date %} <p class="meta">Last updated {{ page.git_date }}</p> {% endif %} </header> <div class="prose"> {{ page.content | safe }} </div> {% if page.tags %} <section class="tags"> {% for tag in page.tags %} <a class="tag" href="/tags/{{ tag }}">{{ tag }}</a> {% endfor %} </section> {% endif %} {% if page.prev_page or page.next_page %} <nav class="series-nav"> {% if page.prev_page %} <a href="{{ page.prev_page.url }}">← {{ page.prev_page.title }}</a> {% endif %} {% if page.next_page %} <a href="{{ page.next_page.url }}">{{ page.next_page.title }} →</a> {% endif %} </nav> {% endif %} </article> {% if related %} <aside class="related"> <h3>Related</h3> <ul> {% for p in related %} <li><a href="{{ p.url }}">{{ p.title }}</a></li> {% endfor %} </ul> </aside> {% endif %} </div> {% endblock %}
Example: a compact section listing
A layouts/list.html that shows a compact table-style listing instead of cards:
{% extends "base.html" %} {% block main %} <section class="list-page"> <h1>{{ page.title }}</h1> {% if page.content %} <div class="intro">{{ page.content | safe }}</div> {% endif %} <table class="page-table"> <thead> <tr><th>Page</th><th>Updated</th><th>Tags</th></tr> </thead> <tbody> {% for p in pages %} <tr> <td><a href="{{ p.url }}">{{ p.title }}</a></td> <td>{{ p.git_date | default(value="—") }}</td> <td> {% for tag in p.tags %} <a href="/tags/{{ tag }}">{{ tag }}</a> {% endfor %} </td> </tr> {% endfor %} </tbody> </table> {% if pagination is defined and pagination.total_pages > 1 %} <nav class="pager"> {% if pagination.has_prev %}<a href="{{ pagination.prev_url }}">Previous</a>{% endif %} <span>{{ pagination.current_page }} / {{ pagination.total_pages }}</span> {% if pagination.has_next %}<a href="{{ pagination.next_url }}">Next</a>{% endif %} </nav> {% endif %} </section> {% endblock %}
Example: using data/ for dynamic content
A template that lists team members from data/team.toml:
data/team.toml:
[[members]] name = "Alice" role = "Maintainer" link = "https://github.com/alice" [[members]] name = "Bob" role = "Contributor" link = "https://github.com/bob"
In any template:
<section class="team"> {% for member in data.team.members %} <div class="member"> <a href="{{ member.link }}">{{ member.name }}</a> <span>{{ member.role }}</span> </div> {% endfor %} </section>
data is a map keyed by filename (without .toml), so data/team.toml becomes data.team.
Example: page-level extra fields
Extra frontmatter fields are available in templates via page.extra:
--- title: Release 1.4 date: 2026-03-01 release_version: "1.4.0" release_tag: "stable" ---
In single.html:
{% if page.extra.release_version %} <div class="release-badge {{ page.extra.release_tag }}"> Version {{ page.extra.release_version }} </div> {% endif %}
Tips
Use | safe only on values you control. Rendered Markdown (page.content) and shortcode output is already sanitized by Everlock. Do not use | safe on user-submitted or external data.
Check existence before accessing nested fields. If a page has no tags, page.tags is an empty list (safe to loop over). If a page has no prev_page, the variable is null — use {% if page.prev_page %} before accessing .url or .title on it.
Template changes are live on next request. Everlock reads templates from the store on each request. Push a template change with git push and reload the page to see it.