Skip to main content

UI components for Python using Pydantic and Jinja2 templates

Project description

PyJinHx

Build reusable, type-safe UI components for template-based web apps in Python. PyJinHx combines Pydantic models with Jinja2 templates to give you template discovery, component composition, and JavaScript bundling.

Installation

pip install pyjinhx

Core ideas

You can use PyJinHx in two ways, and mix them:

  • Python-side: render a typed Python component instance (BaseComponent.render()).
  • Template-side: render HTML-like source with PascalCase custom tags (Renderer(...).render(source)).

Python-to-HTML Example

Start here if you want a typed component library.

Step 1: Define Component Classes

# components/ui/button.py
from pyjinhx import BaseComponent

class Button(BaseComponent):
    id: str
    text: str
    variant: str = "default"
# components/ui/card.py
from pyjinhx import BaseComponent
from components.ui.button import Button

class Card(BaseComponent):
    id: str
    title: str
    action_button: Button
    menu_items: list[Button]

Step 2: Create Templates

<!-- components/ui/button.html (auto-discovered) -->
<button id="{{ id }}" class="btn btn-{{ variant }}">{{ text }}</button>
<!-- components/ui/card.html (auto-discovered) -->
<div id="{{ id }}" class="card">
    <h2>{{ title }}</h2>
    <div class="action">
        <p>Button: {{ action_button.props.text }}</p>
        {{ action_button }}
    </div>
    <ul class="menu">
        {% for item in menu_items %}
        <li>{{ item }}</li>
        {% endfor %}
    </ul>
</div>

Step 3: Use in Python

from components.ui.card import Card
from components.ui.button import Button

card = Card(
    id="form-card",
    title="User Form",
    action_button=Button(id="submit", text="Submit", variant="primary"),
    menu_items=[
        Button(id="home", text="Home"),
        Button(id="about", text="About")
    ]
)
html = card.render()

HTML-like syntax (custom tags)

Start here if you prefer composing pages with an HTML-like string.

<!-- templates/card.html -->
<div id="{{ id }}" class="card">
    <h2>{{ title }}</h2>
    {{ content }}
</div>
<!-- templates/button.html -->
<button id="{{ id }}" class="btn btn-{{ variant }}">{{ text }}</button>
from jinja2 import Environment, FileSystemLoader
from pyjinhx import Renderer

renderer = Renderer(Environment(loader=FileSystemLoader("./templates")), auto_id=True)
html = renderer.render('''
    <Card title="Welcome">
        <Button text="Get Started" variant="primary"/>
        <Button text="Learn More" variant="secondary"/>
    </Card>
''')

This mode supports:

  • Registered classes: if Button(BaseComponent) exists, its Pydantic fields are enforced when <Button .../> is instantiated.
  • Generic tags: if there is no registered class, a generic BaseComponent is used as long as the template file can be found.

Use custom tags inside component templates

BaseComponent.render() expands <PascalCase /> tags found inside a component template, so component templates can compose other components directly:

<!-- components/ui/page.html -->
<div id="{{ id }}">
  <Button id="save" text="Save"/>
</div>

JavaScript & extra assets

  • Component-local JS: if a component class MyWidget has a sibling file my-widget.js, it is auto-collected and injected once at the root render.
  • Extra JS: pass js=[...] with file paths; missing files are ignored.
  • Extra HTML files: pass html=[...] with file paths; they are rendered and exposed in the template context by filename stem (e.g. extra_content.htmlextra_content.html wrapper). Missing files raise FileNotFoundError.

Configuration

  • Default environment: Renderer.get_default_renderer() auto-detects a project root and uses FileSystemLoader(root).
  • Override: call Renderer.set_default_environment(Environment(loader=FileSystemLoader(...))) for explicit control (tests do this).

Key Benefits

  • Type Safety: Pydantic models provide validation and IDE support
  • Composability: Nest components easily—works with single components, lists, and dictionaries
  • Automatic Template Discovery: Place templates next to component files—no manual paths
  • JavaScript Bundling: Automatically collects and bundles .js files from component directories
  • Flexible: Use Python classes for reusable components, HTML syntax for quick page composition

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

pyjinhx-0.2.0.tar.gz (31.5 kB view details)

Uploaded Source

Built Distribution

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

pyjinhx-0.2.0-py3-none-any.whl (13.0 kB view details)

Uploaded Python 3

File details

Details for the file pyjinhx-0.2.0.tar.gz.

File metadata

  • Download URL: pyjinhx-0.2.0.tar.gz
  • Upload date:
  • Size: 31.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for pyjinhx-0.2.0.tar.gz
Algorithm Hash digest
SHA256 32308a79dc49b7d82f990ac3488b19c7eac354167559f5b1d985c804e596ab02
MD5 d95799974030e1833cde7cc31533be5e
BLAKE2b-256 709a14478006388721fa19f53e7faf23d1d3de7ed8d91987a42706875b6fba8b

See more details on using hashes here.

File details

Details for the file pyjinhx-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: pyjinhx-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 13.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for pyjinhx-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c04532a154c9fc03d446768305e978daebe49c9033ed14519c2d2dfc663975cd
MD5 372ade0279e967ce78292c12c1d3c2ff
BLAKE2b-256 1c9f170072ce3b549a709aabac76ff0ad6478702e0ab4db735ce036d5342a40b

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