Nesting¶
PyJinHx makes it easy to compose components together. You can nest single components, lists of components, or dictionaries of components.
Two nesting styles, two id rules
There are two ways to nest:
- Python field values (this page) — you build child instances yourself; give each child an explicit
id(auto-generatedpjx-<n>ids are not stable hooks). - PascalCase
<Tag/>in templates (see PascalCase Tags) — the renderer instantiates children for you and can auto-generate theidwhenauto_id=True(the default).
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>
How it works
When a field value is a BaseComponent, PyJinHx wraps it in a NestedComponentWrapper before rendering. Use {{ field }} to output the HTML, and {{ field.props.X }} to access the original component's properties. This also applies to components inside lists and dicts.
Lists of Components¶
Use a list to render multiple components:
<!-- 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 Widget(BaseComponent):
id: str
content: str
class Container(BaseComponent):
id: str
items: list[Button | Card | Widget]
Dictionaries of Components¶
Use dictionaries for named component collections:
<!-- 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"),
}
)
Deep Nesting¶
Components can be nested to any depth. Reusing the Button and Card classes from above:
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.