User Guide - Templates

  • Overview
  • For Developers
  • For Authors
  • Documentation
  • Download
  • Blueprints
  • Templates

    Templates go into the /templates subdirectory, and are written in the Ginger template language. Ginger is very similar to Jinja2 or Twig; if you’re familiar with Django templates, you will also feel at home quickly.

    Ginger Basics

    Ginger is basically HTML, plus some extra syntax to put dynamic stuff in your HTML; we call this “interpolation”. The syntax for interpolation is {{ }}, and the simplest form just injects one value from the route’s data into the HTML as-is.

    For example, if the greeting value from the route is "hello", then the following template snippet:

    <div class="greeting">{{ greeting }}</div>

    …will produce the following HTML:

    One thing to note here is that Ginger automatically HTML-encodes any data you pass it, unless it is HTML-encoded already; this means that you will not generally encounter XSS vulnerabilities, nor excessive HTML-encoding (i.e., seeing “special” HTML characters in the output such as &amp; or &gt;).

    Literal Values


    Ginger supports numeric literals in digital notation:

    <span>{{ 500 }}</span>

    …renders as:

    A range of basic math operators is available, e.g.:

    <span>{{ 5 * 5 + 1 }}</span>


    String literals can use single quotes, or double quotes:

    <span>{{ "Hello" }}, {{ 'world' }}!</span>

    While this may not seem terribly useful, strings can be useful to avoid writing out excessive HTML-encoding by hand:

      This is what a div tag looks like:
      {{ "<div>content</div>" }}

    String literals are also useful in more complex expressions.

    Strings can be concatenated with the ~ operator; applying it will also automatically convert both sides into strings, so you can use it to concatenate a number onto a string:

    <span>{{ "the winning number is " ~ 23 }}</span>


    Not all variables are simple values that you interpolate as-is; Ginger also supports key-value collections known as dictionaries. Here’s an example:

    <div class="name">{{ user.name }}</div>

    Assuming that the user value from the route is something like {"username": "johndoe", "fullname": "John Doe", "id": 23}, then the above will render as:

    Alternatively, dictionary access can be achieved using [ ] syntax:

    <div class="name">{{ user["name"] }}</div>

    Note that in this case, the property name needs to be quoted; this is because the [ ] syntax accepts arbitrary expressions. This works almost exactly like in JavaScript.


    Lists are similar to dictionaries, but they have no explicit keys. You can, however, access elements by (0-based) index:

    <span class="third-item">{{ items[2] }}</span>

    With items bound to [ "foo", "bar", "baz" ], this renders as:


    Lists are most useful, however, for loops. Ginger has a loop construct called for, which looks like this:

    {% for item in items %}
      <li>{{ item }}</li>
    {% endfor %}

    With the same binding for items, this will render as:


    The basic conditional construct is if:

    {% if user.name == null %}
    <span class="anonymous-user">Guest</span>
    {% else %}
    <span class="registered-user">{{ user.name }}</span>
    {% endif %}

    Which, if user exists and has a name property of value `“John Doe”, renders as:


    Ginger comes with a wide range of filters. You can pass variables through filters before interpolating them using the | syntax. For example, the default filter replaces a value with a default value if it is empty:

    <span>{{ user.name|default("anonymous") }}</span>

    Another useful filter is ellipse, which shortens its input to a maximum length, appending an ellipsis (…) as needed:

    <div>{{ page.content|ellipsis(100) }}</div>

    For a full list of supported filters, please refer to the Ginger Documentation.


    Filters and functions are basically the same thing, the only difference is syntax. For example, using default as a function in the above example would look like this:

    <span>{{ default(user.name, "anonymous") }}</span>

    Ginger in Sprinkles

    Ginger is a powerful and extensible template language. On top of what it can do out of the box, Sprinkles adds some functionality of its own, and it uses Ginger’s flexible dynamic data structures to make the data you get from backends quite powerful.

    Special Functionality Of Data Objects

    Rich Text Content

    Many data formats that Sprinkles can read (DOCX, HTML, Markdown, Textile, ReStructuredText, …) are exposed as “rich text”. Such documents, by default, render as HTML, reproducing as much of the markup as possible. But they can do more:

    The request Object

    Every page exposes a request object that contains information about the current HTTP request, particularly:

    Extra Functions Sprinkles Adds