Nunjucks

Nunjucks is a template language implemented in JavaScript. It supports features seen in most programming languages.

VS Code extensions

The VS Code extension "Nunjucks" (ronnidc.nunjucks) applies syntax highlighting in .njk files.

The VS Code extension "Nunjucks Snippets" (luwenjiechn.nunjucks-vscode-snippets) defines Nunjucks snippets to simplifying writing Nunjucks constructs in .njk files.

Configuration

TODO: Cover other nunjucks-specific configuration.

Data types

Nunjucks essentially supports the same data types as JavaScript. These include:

Operators

Nunjucks supports these mathematical operators:

Nunjucks supports these comparison operators from JavaScript:

Nunjucks supports these logical operators:

Comments

The syntax for comments is:

{# some comment #}

Variables

To define or modify a variable:

{% set name = value %}

Variables defined at the top-level are global. Otherwise they are scoped to the construct in which they are defined.

Rendering

To render an expression, enclose it in double-curly braces. For example:

{{ dog.name }}

Filters

Nunjucks can render the result of passing a value through a filter. There are many provided filters and custom filters can be implemented. The provided filters are documented at Builtin Filters. They include abs, batch, capitalize, center, default, dictsort, dump, escape, first, float, forceescape, groupby, indent, int, join, last, length, list, lower, nl2br, random, rejectattr, replace, reverse, round, safe, selectattr, slice, sort, string, striptags, sum, title, trim, truncate, upper, urlencode, urlize, and wordcount.

There are too many to describe, but here are some highlights:

Here is an example of applying the upper filter to a string:

{{ dog.name | upper }}

Another syntax is available for applying a filter to a large amount of content. For example:

{% filter upper %}
Mark is a software engineer at Object Computing, Inc.
{% endfilter %}

This form can only contain literal content, not other Nunjucks constructs.

Nunjucks also supports defining custom filters. When using 11ty, they can be defined in the .eleventy.js. For example, this filter writes the value of an expression to the devtools console.

eleventyConfig.addFilter('log', console.log);

This filter will be added to 11ty in version 11.

Conditional logic

Content can be conditionally included using an if statement. For example:

{% if color === 'yellow' %}
sunny
{% elif color === 'blue' %}
rainy
{% else %}
unknown
{% endif %}

Nunjucks supports using and if for an odd kind of ternary operator. For example, this outputs "yellow" if happy is true.

{{ "yellow" if happy }}

This is similar, but outputs "gray" if happy is false.

{{ "yellow" if happy else "gray" }}

Iteration

A for loop iterates over the elements of an array or the properties of an object and renders content for each element. An optional else block specifies content to render if the array is empty.

If the variable dogs holds an array of objects, we can iterate over the array as follows:

{% for dog in dogs %}
<p>{{ dog.name }} is a {{ dog.breed }}.</p>
{% else %}
<p>Who let the dogs out?</p>
{% endfor %}

The current loop index is available in loop.index (starts from 1) and loop.index0 (starts from 0).

If the variable dog holds an object, we can iterate over its properties as follows:

{% for key, value in dog %}
<p>{{key}} = {{value}}</p>
{% endfor %}

There is also support for asynchronous versions of this (asyncEach and asyncAll) that most sites will not need. It is documented at Asynchronous Support.

Function calls

JavaScript functions can be called using the same syntax as JavaScript. For example, this calls a function and renders its result:

{{ someFunction(arg1, arg2) }}

This calls a function and assigns its result to a variable:

{% set name = someFunction(arg1, arg2) }}

Regular expressions

Regular expressions are defined by beginning with r/. For example:

{% set re = r/^a.*z$/i %}
{% if re.test(dog.name) %}
This dog goes from a to z!
{% endif %}

The i option at the end of the regular expression signifies case-insensitive matching.

Sanitizing

When rendering HTML from a potentially untrusted source, use the safe filter to sanitize it. For example:

{{ someHtml | safe }}

Includes

One template can include another. This allows a template to be reused in many places. For example:

{% include "snippet.html" %}

This is useful when the content to be included doesn't require any data to be supplied. When data is required, consider using Nunjucks macros which are described next.

Macros

Macros are like functions that have parameters and render something based on those. Parameters can have default values that are used when a value is not provided. For example:

{% macro dogP(name, breed, gender='unknown') %}
<p>{{name}} is a {{gender}} {{breed}}.</p>
{% endmacro %}

A macro call looks like a function call. For example:

{% for dog in collections.dogsByName %}
{{ dogP(dog.data.name, dog.data.breed, dog.data.gender) }}
{% endfor %}

Arguments can be specified positionally or by name. The previous example used positional arguments. The next example uses named arguments.

{% for dog in collections.dogsByName %}
{{ dogP(gender=dog.data.gender, breed=dog.data.breed, name=dog.data.name) }}
{% endfor %}

Macros can be defined in a .njk file and imported where needed. For example, the following imports the file _includes/macros.njk:

{% import 'macros.njk' as macros with context %}

To call a macro named "demo" that is defined in macros.njk,

{{ macros.demo(arguments) }}

For an example of using this approach, see how _includes/layout.njk uses macros to render the left nav.

A call block enables passing enclosed text to a macro.

TODO: Maybe Nunjucks macros can be used as an alternative to 11ty shortcodes.

Template inheritance

Blocks define named locations in a template where content can be inserted. They can contain default content that a using template can override.

The extends tag inherits another template. This is followed by block tags that supply content to be inserted.

The super function is used in conjunction with template inheritance to render the contents of a parent block.

For more detail, see Template Inheritance.

Whitespace

By default all whitespace is retained. To trim whitespace before a construct, begin with {%- instead of {%. To trim whitespace after a construct, end with -%} instead of %}. Zach Leatherman recommends only using {%-.

Global functions

Nunjucks provides some predefined functions that address common needs.

Documenting Nunjucks syntax

To escape Nunjucks syntax so it is rendered as-is instead of being evaluated, wrap it in a raw block. It may also be desirable to wrap the text in a Markdown fenced block. There is no support for Nunjucks syntax, but Liquid syntax is close enough. In the example below, the apostrophe characters should really be backticks.

{% raw %}
'''liquid
Some Nunjucks syntax goes here.
'''
{% endraw %}

verbatim is an alias for raw.