Skip to main content

Streamlined way to build and reuse your Jinja2 templates from code

Project description

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_component has been added after environment creation and not typed into Environment class. There is a workaround using library register_component function or _ComponentsEnvironment or protocol class with register_component method.

Usage

  1. Install the library.

    pip install jinja2-components
    
  2. 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])
    
  3. 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")
    
  4. 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 to True for block tags that wrap content (default: False).

Methods:

  • get_context(*args, **kwargs): Class method to prepare the rendering context. Defaults to returning kwargs.
  • 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jinja2_components-1.0.0.tar.gz (10.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jinja2_components-1.0.0-py3-none-any.whl (6.7 kB view details)

Uploaded Python 3

File details

Details for the file jinja2_components-1.0.0.tar.gz.

File metadata

  • Download URL: jinja2_components-1.0.0.tar.gz
  • Upload date:
  • Size: 10.1 kB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for jinja2_components-1.0.0.tar.gz
Algorithm Hash digest
SHA256 c0dc616ab2c419e439c7025db7bbc71c001071ed05dbd25f9d92a2fca6ef1306
MD5 83ad0105f519ea82bdd50fd1c6cb0baa
BLAKE2b-256 d075b7c1b5007cbfbc357c07fff4b658bcf4455cac3355e48389d3a05a717275

See more details on using hashes here.

File details

Details for the file jinja2_components-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: jinja2_components-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 6.7 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for jinja2_components-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 08ec77f8d76adf2c7ff86583966d2b09bbde841257a7209bd2cd1cfecf048ca3
MD5 8f13ffa900ef63eb701dff4ddbb7a35e
BLAKE2b-256 ab94b479fb54e82f0021c425e3124e6096e967239c6c07b91e15bcc2f2942d77

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page