Basic Usage

Jinja2 Fragments follows the principle of Locality of Behavior by allowing you to maintain a single template file for both full page and partial rendering. This eliminates the need to create separate template files for each block you want to render independently.

Core Concepts

With traditional Jinja2, if you want to render a block by itself and as part of another page, you would typically:

  1. Put that block in a separate file

  2. Use the include tag or Jinja Partials on the wrapping template

With Jinja2 Fragments, you can:

  1. Define all blocks in a single template file

  2. Render the full template when needed

  3. Render specific blocks from that template when needed

This approach is especially useful when working with htmx or similar libraries that fetch partial HTML content.

Simple Block Rendering

Let’s start with a basic example using vanilla Jinja2. Consider the following template page.html.jinja2:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>This is the title</title>
</head>
<body>
    <h1>This is a header</h1>
    {% block content %}
    <p>This is the magic number: {{ magic_number }}.</p>
    {% endblock %}
</body>
</html>

If you want to render only the content block, you can use render_block like this:

from jinja2 import Environment, FileSystemLoader, select_autoescape
from jinja2_fragments import render_block

environment = Environment(
    loader=FileSystemLoader("my_templates"),
    autoescape=select_autoescape(("html", "jinja2")),
)
rendered_html = render_block(
    environment, "page.html.jinja2", "content", magic_number=42
)

This will only render:

<p>This is the magic number: 42.</p>

Note

The render_block function takes the same arguments as Jinja2’s render_template function, plus an additional argument for the block name to render.

Multiple Blocks Rendering

Jinja2 Fragments also allows you to render multiple blocks at once with the render_blocks function (notice the plural):

from jinja2 import Environment, FileSystemLoader, select_autoescape
from jinja2_fragments import render_blocks

environment = Environment(
    loader=FileSystemLoader("my_templates"),
    autoescape=select_autoescape(("html", "jinja2")),
)
rendered_html = render_blocks(
    environment, "page.html.jinja2", ["header", "content"], magic_number=42
)

Note

Rendering multiple blocks is particularly useful for implementing out-of-band updates when using htmx, allowing you to update multiple parts of a page in a single request.

Rendering Blocks from Within Templates

You can also call render_block and render_blocks directly from within Jinja2 template expressions. This is useful when a template needs to compose fragments from other template files.

To enable this, call setup_globals() on your Jinja2 environment:

from jinja2 import Environment, FileSystemLoader, select_autoescape
from jinja2_fragments import setup_globals

environment = Environment(
    loader=FileSystemLoader("my_templates"),
    autoescape=select_autoescape(("html", "jinja2")),
)
setup_globals(environment)

Once installed, you can use render_block and render_blocks in any template rendered with that environment:

<div id="customer">
  {{ render_block("customer/edit.html.jinja2", "customer", customer=invoice.customer) }}
</div>

{# Render multiple blocks at once #}
{{ render_blocks("dashboard.html.jinja2", ["stats", "chart"], user=user) }}

The current template context is automatically forwarded to the rendered block(s). Any keyword arguments you pass will override individual context variables.

Note

setup_globals automatically selects the correct sync or async implementation based on environment.is_async, so it works with both synchronous and asynchronous environments. Existing globals named render_block and render_blocks are preserved.