How to Combine Jinja Templates with Air Tags in Python Views
Use JinjaRenderer with as_string=True to render Jinja templates into SafeStr objects that can be embedded directly inside Air Tag compositions.
The feldroy/air repository provides a seamless mechanism for mixing traditional Jinja2 templating with its component-based Air Tag system. By leveraging the as_string parameter in JinjaRenderer, developers can generate HTML from Jinja templates and inject that output into Air Tag hierarchies within the same view function.
Understanding the JinjaRenderer and SafeStr Mechanism
Air’s templating integration centers on two key components: the JinjaRenderer class and the SafeStr utility.
The JinjaRenderer.__call__ method, defined in src/air/templating.py (lines 118-148), handles template rendering. When invoked with as_string=True, the renderer extracts the response body from the Jinja2 template, decodes it to UTF-8, and wraps the result in a SafeStr object from air.tags.utils.
SafeStr is a thin subclass of Python’s built-in str that signals to Air’s rendering engine that the content is already safe HTML. This prevents automatic escaping when the string is inserted into parent Air Tags, allowing seamless composition of Jinja-generated markup with programmatically constructed Air Tag trees.
Implementing Combined Jinja and Air Tag Views
Basic Implementation with as_string=True
To combine Jinja templates with Air Tags, initialize a JinjaRenderer pointing to your templates directory, then call it with as_string=True inside your view function:
import air
app = air.Air()
jinja = air.JinjaRenderer("templates")
@app.page
def hybrid_view(request: air.Request) -> air.BaseTag:
# Render Jinja template to SafeStr
jinja_output = jinja(
request,
"content.html",
as_string=True
)
# Embed in Air Tag layout
return air.layouts.mvpcss(
air.Title("Hybrid Page"),
jinja_output, # Jinja content injected here
)
Complete Working Example
The repository includes a runnable example in examples/jinja_in_air_tags.py demonstrating this pattern. The corresponding template at examples/jinja_in_air_tags.html contains standard Jinja markup:
<h1>Hello from Jinja</h1>
<p>This content is rendered by Jinja2 but embedded in an Air Tag layout.</p>
The view function combines this template with Air’s mvpcss layout:
@app.page
def index(request: air.Request) -> air.BaseTag:
jinja_html = jinja(request, "jinja_in_air_tags.html", as_string=True)
return air.layouts.mvpcss(
air.Title("Home Page"),
jinja_html,
)
Alternative: Returning Raw HTMLResponse
If you do not need to embed Jinja output inside Air Tags, omit the as_string parameter. This returns a standard Starlette HTMLResponse directly:
@app.page
def plain_jinja(request: air.Request) -> air.Response:
return jinja(request, "plain.html") # Returns HTMLResponse
This approach is suitable for pages that use Jinja exclusively without Air Tag composition.
Summary
- Use
as_string=TrueinJinjaRendererto obtain aSafeStrobject instead of anHTMLResponse. SafeStrmarks Jinja-generated HTML as safe for embedding in Air Tags without escaping.- Reference implementation resides in
src/air/templating.py, specifically theJinjaRenderer.__call__method (lines 118-148). - Runnable examples are available in
examples/jinja_in_air_tags.pyandtests/test_templating.py(lines 101-112).
Frequently Asked Questions
What is SafeStr in Air?
SafeStr is a string subclass defined in air.tags.utils that indicates to Air’s rendering engine that the content is already safe HTML and should not be escaped. When JinjaRenderer is called with as_string=True, it returns a SafeStr instance containing the rendered template output, allowing seamless insertion into Air Tag trees.
Can I use multiple Jinja templates in one Air Tag?
Yes. You can call JinjaRenderer multiple times with different template names, each time using as_string=True to obtain separate SafeStr objects. These can then be passed as multiple children to a parent Air Tag or layout, effectively combining content from several Jinja templates within a single view response.
Where is JinjaRenderer defined in the Air source code?
JinjaRenderer is implemented in src/air/templating.py. The core logic for the as_string functionality resides in the __call__ method between lines 118 and 148, where the method constructs the Jinja context, renders the template, and conditionally wraps the output in SafeStr based on the as_string parameter.
How do I test views that combine Jinja and Air Tags?
The test suite in tests/test_templating.py (lines 101-112) provides examples of testing this integration. You can instantiate JinjaRenderer with a test templates directory, invoke it with as_string=True, and assert that the returned object is a SafeStr instance that can be composed with Air Tags. For integration testing, use Air’s test client to verify the final rendered HTML output contains both the Jinja-generated content and the Air Tag markup.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →