Syntax
Hwaro uses Crinja, a Jinja2-compatible template engine. This page covers the essential syntax.
Variables
Print values with double braces:
{{ page.title }}
{{ site.description }}
{{ content }}
Comments
{# This is a comment #}
Conditionals
{% if page.description %}
<meta name="description" content="{{ page.description }}">
{% endif %}
With else:
{% if page.draft %}
<span class="badge">Draft</span>
{% else %}
<span class="badge">Published</span>
{% endif %}
With elif:
{% if page.section == "blog" %}
<article class="post">{{ content | safe }}</article>
{% elif page.section == "docs" %}
<div class="documentation">{{ content | safe }}</div>
{% else %}
<main>{{ content | safe }}</main>
{% endif %}
Loops
{% for p in section.pages %}
<li><a href="{{ p.url }}">{{ p.title }}</a></li>
{% endfor %}
With index:
{% for tag in page.tags %}
{% if not loop.first %}, {% endif %}
{{ tag }}
{% endfor %}
Loop variables:
| Variable | Description |
|---|---|
| loop.index | Current iteration (1-based) |
| loop.index0 | Current iteration (0-based) |
| loop.first | True on first iteration |
| loop.last | True on last iteration |
| loop.length | Total items |
Template Inheritance
Base Template
templates/base.html:
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{{ site.title }}{% endblock %}</title>
{{ highlight_css | safe }}
</head>
<body>
{% block content %}{% endblock %}
{{ highlight_js | safe }}
</body>
</html>
Child Template
templates/page.html:
{% extends "base.html" %}
{% block title %}{{ page.title }} - {{ site.title }}{% endblock %}
{% block content %}
<article>
<h1>{{ page.title }}</h1>
{{ content | safe }}
</article>
{% endblock %}
Includes
Include partial templates:
{% include "partials/header.html" %}
<main>{{ content | safe }}</main>
{% include "partials/footer.html" %}
Variables
Set variables:
{% set author = page.authors | first %}
<span>By {{ author }}</span>
Filters
Transform values with the pipe operator:
{{ page.title | upper }}
{{ content | safe }}
{{ page.date | date("%B %d, %Y") }}
{{ page.authors | join(", ") }}
See Filters for all available filters.
Tests
Evaluate conditions:
{% if page.url is startswith("/blog/") %}
<span>Blog post</span>
{% endif %}
{% if page.description is empty %}
<meta name="description" content="{{ site.description }}">
{% endif %}
See Filters for all available tests.
Whitespace Control
Trim whitespace with minus signs:
{%- if condition -%}
trimmed
{%- endif -%}
Raw Blocks
Output literal Jinja syntax:
{% raw %}
{{ this will not be parsed }}
{% endraw %}
Operators
Comparison
| Operator | Description |
|---|---|
| `==` | Equal |
| `!=` | Not equal |
| `<` | Less than |
| `>` | Greater than |
| `<=` | Less or equal |
| `>=` | Greater or equal |
Logical
| Operator | Description |
|---|---|
| `and` | Both true |
| `or` | Either true |
| `not` | Negation |
{% if page.section == "blog" and not page.draft %}
<article>{{ content | safe }}</article>
{% endif %}
Membership
{% if "tutorial" in page.tags %}
<span class="badge">Tutorial</span>
{% endif %}
Common Patterns
Active Navigation
<nav>
<a href="/"{% if page.url == "/" %} class="active"{% endif %}>Home</a>
<a href="/blog/"{% if page.section == "blog" %} class="active"{% endif %}>Blog</a>
</nav>
Conditional Meta Tags
<head>
{% if page.description %}
<meta name="description" content="{{ page.description }}">
{% endif %}
{{ og_all_tags | safe }}
</head>
Section-Based Layout
<body data-section="{{ page.section }}">
{% if page.section == "docs" %}
{% include "partials/sidebar.html" %}
{% endif %}
<main>{{ content | safe }}</main>
</body>
Loop with Empty Check
{% if section.pages %}
<ul>
{% for p in section.pages %}
<li><a href="{{ p.url }}">{{ p.title }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No articles yet.</p>
{% endif %}
See Also
- Data Model — Available variables
- Functions — Built-in functions
- Filters — Filters and tests