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:
Put that block in a separate file
Use the include tag or Jinja Partials on the wrapping template
With Jinja2 Fragments, you can:
Define all blocks in a single template file
Render the full template when needed
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.