Documentation

Last updated in git: 2026-06-11

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

VariableTypeContent
site.titlestringSite title from site.toml
site.descriptionstringSite description from site.toml
site.base_urlstringBase URL from site.toml
site.timezonestringOptional site timezone used by today() and date formatting
site.nav.linkslistNavigation links, each with .label and .url
datamapAll .toml files from the data/ directory

In single.html (content pages)

VariableTypeContent
page.titlestringTitle from frontmatter
page.contentstringRendered HTML of the page body
page.summarystringHTML of content before <!--more-->, or empty
page.tagslistTag strings
page.datestringFrontmatter date
page.git_datestringDate of the last git commit for this file
page.urlstringPage URL path, e.g. /docs/reference
page.extramapScalar extra frontmatter fields
page.relatedlistUp to 5 related pages (by shared tags), each with .title, .url, .tags
page.prev_pageobjectPrevious page in a series, with .title and .url
page.next_pageobjectNext page in a series, with .title and .url
page.uses_mermaidboolWhether the page contains a Mermaid diagram

In list.html and custom section templates

VariableTypeContent
page.titlestringSection title from _index.md or URL path
page.contentstringRendered HTML from _index.md body
pageslistChild pages, each with .title, .url, .tags, .date, .git_date
paginationobjectPagination state (only when paginate_by is set in site.toml)
pagination.current_pageintCurrent page number
pagination.total_pagesintTotal number of pages
pagination.has_prevboolWhether a previous page exists
pagination.has_nextboolWhether a next page exists
pagination.prev_urlstringURL of the previous page
pagination.next_urlstringURL 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.


Read next

sites templates markdown tera