Skip to content

Nesting

PyJinHx makes it easy to compose components together. You can nest single components, lists of components, or dictionaries of components.

Direct Nesting

Pass a component as a field value:

from pyjinhx import BaseComponent


class Button(BaseComponent):
    id: str
    text: str


class Card(BaseComponent):
    id: str
    title: str
    action: Button  # Nested component
<!-- card.html -->
<div id="{{ id }}" class="card">
    <h2>{{ title }}</h2>
    <div class="actions">
        {{ action }}
    </div>
</div>
card = Card(
    id="hero",
    title="Welcome",
    action=Button(id="cta", text="Get Started")
)
html = card.render()

Accessing Nested Component Properties

Nested components are wrapped in NestedComponentWrapper, giving you access to both the rendered HTML and the original props:

<!-- card.html -->
<div id="{{ id }}" class="card">
    <h2>{{ title }}</h2>

    <!-- Render the component -->
    {{ action }}

    <!-- Access component properties -->
    <p>Button text: {{ action.props.text }}</p>
    <p>Button ID: {{ action.props.id }}</p>
</div>

Lists of Components

Use a list to render multiple components:

class ButtonGroup(BaseComponent):
    id: str
    buttons: list[Button]
<!-- button_group.html -->
<div id="{{ id }}" class="button-group">
    {% for button in buttons %}
        {{ button }}
    {% endfor %}
</div>
group = ButtonGroup(
    id="actions",
    buttons=[
        Button(id="save", text="Save"),
        Button(id="cancel", text="Cancel"),
        Button(id="delete", text="Delete"),
    ]
)

Accessing List Item Properties

<div id="{{ id }}" class="button-group">
    {% for button in buttons %}
        <div class="button-wrapper" data-text="{{ button.props.text }}">
            {{ button }}
        </div>
    {% endfor %}
</div>

Mixed Collections

Combine different types in lists and dicts:

class Container(BaseComponent):
    id: str
    items: list[Button | Card | Widget]
{% for item in items %}
    <div class="item">{{ item }}</div>
{% endfor %}

Dictionaries of Components

Use dictionaries for named component collections:

class Dashboard(BaseComponent):
    id: str
    widgets: dict[str, Widget]
<!-- dashboard.html -->
<div id="{{ id }}" class="dashboard">
    <aside>{{ widgets.sidebar }}</aside>
    <main>{{ widgets.main }}</main>
    <footer>{{ widgets.footer }}</footer>
</div>
dashboard = Dashboard(
    id="main",
    widgets={
        "sidebar": Widget(id="nav", content="Navigation"),
        "main": Widget(id="content", content="Main content"),
        "footer": Widget(id="foot", content="Footer"),
    }
)

Wrappers

The inner content of a tag becomes {{ content }} in the component template:

html = renderer.render("""
    <Card title="Note">
        This text becomes the content variable.
    </Card>
""")

Deep Nesting

Components can be nested to any depth:

class Button(BaseComponent):
    id: str
    text: str


class Card(BaseComponent):
    id: str
    title: str
    action: Button


class Page(BaseComponent):
    id: str
    title: str
    main_card: Card
page = Page(
    id="home",
    title="Welcome",
    main_card=Card(
        id="hero",
        title="Get Started",
        action=Button(id="cta", text="Sign Up")
    )
)

html = page.render()

The rendering happens recursively - nested components are rendered before their parents.