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(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, .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.