Skip to Content

Template Rendering with Jinja easy

Jinja is the server-side templating engine used throughout InvenioRDM for rendering HTML pages.
NRP repositories build on top of this system and use Jinja extensively for page layout, custom UI views, and template overrides.

In this page we will focus on creation and usage of custom Jinja templates including how to use them, how templates interact with UI Resources (the NRP Invenio mechanism for generating HTML responses for front-end pages).

If you are more interested in how to change built-in templates with your custom ones, the topic is covered in great detail under the Branding —> Templating docs.

For details on how to bind templates to UI Resource views (using templates mapping, routes, and get_jinjax_macro()), see the UI Resource Views documentation.

Basic Jinja syntax refresher

Here we cover just the most common syntax examples you might come across in a Jinja template. Please refer to the official Jinja Template Designer  docs for a full reference on Jinja syntax.

Variables

Prints a value of a context variable.

<p>{{ user.email }}</p>

Filters

One or more chained filters processing/transforming the value of a context variable.

{{ title | upper }}

Loops

Iterate over iterable context variable values (like lists or tuples).

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

Conditionals

The if statement in Jinja is comparable with the Python if statement. Used to test for a result of a boolean expression.

{% if record.access == "public" %} <p>Public record</p> {% endif %}

Macros

Include another snippet of Jinja code into a template.

{% macro input(name, value='', type='text', size=20) -%} <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}"> {%- endmacro %} <p>{{ input('username') }}</p>

Template inclusion & composition

Reusable shared templates (navbars, footers, panels) can be placed in shared directories and then included where needed:

{% include "branding/header.html" %}

Blocks

Defines extension points of a template or overrides block contents from inherited template (see Template Inheritance)

{% extends "invenio_theme/page.html" %} {% block page_body %} <div class="ui container"> <h1>{{ record.title }}</h1> </div> {% endblock %}

Here a page_body block is defined, overriding content from the same block in invenio_theme/page.html.

Template Inheritance

Provide or extend content of blocks defined in inherited template.

For example, InvenioRDM uses a central base template for almost all repository pages:

invenio_theme/page.html

You typically extend it with extends keyword and provide your own content for the blocks defined by extended template:

{% extends "invenio_theme/page.html" %} {% block page_body %} <div class="ui container"> <h1>{{ record.title }}</h1> </div> {% endblock %}

For cases where you just want to append to the beginning/end of a block, there is the super() keyword.

{% extends "invenio_theme/page.html" %} {% block page_footer %} <p>I'm before the standard footer content.</p> {{ super() }} <p>I follow after the standard footer content.</p> {% endblock %}

This will bring up original block content from the extended template.

Best practices

  1. Keep templates light & simple.
  2. Use templates only for presentational logic.
  3. Use UIResourceConfig to map templates to views.
  4. Never hard-code template filenames inside view methods.
  5. Prefer macros for repeated UI fragments.
  6. Templates should do minimal assumptions and rely mainly on the context passed by UIResource views.
Last updated on