Children & Slots to Twig Blocks
When to Use
Use this when converting React's children, named props that accept JSX, render props, or compound component patterns into Twig blocks and SDC slots.
Decision: Children Pattern Mapping
| React Pattern | SDC Equivalent | Implementation |
|---|---|---|
{children} (single child) |
Default slot | {% block content %}{% endblock %} in Twig, slots: content: in component.yml |
Named prop: header={<Header />} |
Named slot | {% block header %}{% endblock %} in Twig, slots: header: in component.yml |
Multiple named props: icon, title, actions |
Multiple named slots | One {% block %} per slot; all declared in component.yml slots: |
Render prop: renderItem={(item) => ...} |
No direct equivalent | Use Twig {% include %} with context variables, or preprocess to prepare render arrays |
Compound: <Card><Card.Header /><Card.Body /></Card> |
Slots or nested includes | Parent SDC defines slots; caller fills them with include/embed |
{children \|\| <Default />} (fallback) |
Block with default content | {% block content %}Default content{% endblock %} -- Twig blocks support defaults |
Conditional children: {children && <Wrapper>{children}</Wrapper>} |
{% if slot_name %} check |
Slots are truthy when filled; check before rendering wrapper |
Pattern: Single Default Slot
React
function Card({ children }) {
return <div className="card"><div className="card-body">{children}</div></div>;
}
component.yml
slots:
content:
title: Content
description: "Card body content."
Twig
<div {{ attributes.addClass('card') }}>
<div class="card-body">
{% block content %}{% endblock %}
</div>
</div>
Pattern: Multiple Named Slots
React
function Hero({ title, aside, button, children }) {
return (
<div className="hero">
<div className="hero-content">
{aside && <div className="aside">{aside}</div>}
<div>
{title && <h1>{title}</h1>}
{children}
{button}
</div>
</div>
</div>
);
}
component.yml
slots:
aside:
title: Aside
title:
title: Title
text:
title: Text
button:
title: Button
Twig
<div {{ attributes.addClass('hero') }}>
<div class="hero-content">
{% if aside %}
{{ aside }}
{% endif %}
<div>
{% if title %}
<h1 class="text-5xl font-bold">{{ title }}</h1>
{% endif %}
{{ text }}
{{ button }}
</div>
</div>
</div>
Note: SDC slots are rendered by outputting the slot variable name directly ({{ aside }}), not with {% block %}. The {% block %} syntax is used when the SDC is consumed via {% embed %}.
Common Mistakes
- Wrong: Using
{% block %}for slots in the component template → Right: SDC slots arrive as render arrays in template variables; use{{ slot_name }}to output slot content - Wrong: Creating separate SDC components for every sub-piece → Right: SDC registration has overhead; use slots on a single component instead
- Wrong: Trying to iterate over slot contents → Right: Slot content is an opaque render array; if you need iteration, pass data as a prop