Jinja2 Components
Jinja2 Components offers a streamlined way to build and reuse your Jinja2 templates from code, inspired by django-components and jinja2-simple-tags.
Key Ideas
- Modular Design. Break down your templates into reusable components for cleaner code and easier maintenance.
- Simple Syntax. Use Jinja2 syntax to only use your components, lower you templates depth.
- Extensible Framework. Customize your components using Python code.
Known issues
- Typing... Similar to any other Jinja2 extensions library's method
register_componenthas been added after environment creation and not typed intoEnvironmentclass. There is a workaround using libraryregister_componentfunction or_ComponentsEnvironmentor protocol class withregister_componentmethod.
Usage
-
Install the library.
pip install jinja2-components
-
Add extension to the Jinja2 environment using class or by name
jinja2_components.ext.components(jinja2_components.ext.ComponentsExtension).from jinja2 import Environment from jinja2_components import ComponentsExtension env = Environment(extensions=[ComponentsExtension])
-
Define a component and it's template.
from jinja2 import Template from jinja2_components import Component, register_component @env.register_component(name="hello") class Hello(Component): template = Template("hello") # OR @register_component(name="hello", env=env) class Hello(Component): template = Template("hello")
-
Use component inside template as a tag.
template = env.from_string("{% hello %} world") print(template.render()) # hello world
Examples
Standalone tag
@env.register_component(name="hello")
class Hello(Component):
template = Template("hello")
template = env.from_string("{% hello %} world")
print(template.render())
# hello world
Block tag with body
@env.register_component(name="button")
class Button(Component):
template = Template("<button>{{ body }}</button>")
block = True
@classmethod
def get_context(cls, caller):
return {"body": str(caller())}
template = env.from_string("{% button %}Hello!{% endbutton %}")
print(template.render())
# <button>Hello!</button>
Replacing body
@env.register_component(name="base64")
class Base64(Component):
template = Template("{{ result }}")
block = True
@classmethod
def get_context(cls, caller):
content = str(caller()).encode()
return {"result": b64encode(content).decode()}
template = env.from_string("{% base64 %}hello world{% endbase64 %}")
print(template.render())
# aGVsbG8gd29ybGQ=
template = env.from_string("""\
{% base64 as hw_base64 %}hello world{% endbase64 %}\
Base64 of 'hello world': {{ hw_base64 }}
""")
print(template.render())
# Base64 of 'hello world': aGVsbG8gd29ybGQ=
Component in component
If the component's template was set directly, then this template also requires extensions. You can pass extensions where required or as a workaround use env.from_string.
But it possible to use template_str and template_name class variables for later instantiation from environment.
@env.register_component(name="button")
class Button(Component):
template_str = "<button>{{ body }}</button>"
@env.register_component(name="menu")
class Menu(Component):
template_str = """\
<div class="menu">\
{% for btn in buttons %}
{% button body=btn %}\
{% endfor %}
</button>
"""
template = env.from_string("{% menu buttons=[1, 2, 3] %}")
print(template.render())
# <div class="menu">
# <button>1</button>
# <button>2</button>
# <button>3</button>
# </button>
Rendering component from code
The idea behind this feature is to pass arguments and get rendered component inside the code.
@env.register_component(name="button")
class Button(Component):
template_str = "<button>{{ body }}</button>"
@env.register_component(name="menu")
class Menu(Component):
template_str = """\
<div class="menu">\
{% for btn in buttons %}
{% button body=btn %}\
{% endfor %}
</button>
"""
template = env.from_string("{% menu buttons=[1, 2, 3] %}")
print(template.render())
# <div class="menu">
# <button>1</button>
# <button>2</button>
# <button>3</button>
# </button>
print(Menu(env, buttons=[1, 2, 3]))
# <div class="menu">
# <button>1</button>
# <button>2</button>
# <button>3</button>
# </button>
Also it is possible to pass initialized components (because the are strings).
@env.register_component(name="menu")
class Menu(Component):
template_str = """\
<div class="menu">\
{% for btn in buttons %}
{{ btn }}\
{% endfor %}
</button>
"""
rendered = Menu(env, buttons=[Button(env, body=1), Button(env, body=2), Button(env, body=3)])
print(rendered)
# <div class="menu">
# <button>1</button>
# <button>2</button>
# <button>3</button>
# </button>
API
Component
Base class for creating reusable template components.
Class Variables:
template: A pre-compiled Jinja2 template instance.template_str: Template content as a string, compiled using the environment.template_name: Name of a template file to load from the environment.block: Set toTruefor block tags that wrap content (default:False).
Methods:
get_context(*args, **kwargs): Class method to prepare the rendering context. Defaults to returningkwargs.get_template(env, *args, **kwargs): Class method to retrieve or create the template instance.
ComponentsExtension
Jinja2 extension that enables component tag parsing and registration.
Methods:
register_component(name: str): Returns a decorator to register a component class with the specified tag name.
register_component
Helper function for registering components with a Jinja2 environment.
Parameters:
name: The tag name used in templates.env: The Jinja2 environment instance.
Metadata
Release files for jinja2-components 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| jinja2_components-1.0.0.tar.gz | 10.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jinja2_components-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 16.8 kB
Release files / jinja2_components-1.0.0.tar.gz
| Download URL | jinja2_components-1.0.0.tar.gz |
|---|---|
| Size | 10.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c0dc616ab2c419e439c7025db7bbc71c001071ed05dbd25f9d92a2fca6ef1306
|
|
BLAKE2b-256 checksum How to use checksums |
d075b7c1b5007cbfbc357c07fff4b658bcf4455cac3355e48389d3a05a717275
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / jinja2_components-1.0.0-py3-none-any.whl
| Download URL | jinja2_components-1.0.0-py3-none-any.whl |
|---|---|
| Size | 6.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
08ec77f8d76adf2c7ff86583966d2b09bbde841257a7209bd2cd1cfecf048ca3
|
|
BLAKE2b-256 checksum How to use checksums |
ab94b479fb54e82f0021c425e3124e6096e967239c6c07b91e15bcc2f2942d77
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|