Component Slots & Composition
To build modular, reusable UI layouts, RTXUI supports Component Slots. This allows you to write wrapper components (such as layout grids, panels, cards, or dialogs) that receive and arrange arbitrary child markup passed from their parents.
RTXUI supports both default slots (for simple child wrapping) and named slots (for multi-zone layouts).
Default Slots (<slot>)
A default slot acts as a placeholder for any child element nested inside your custom component's tag.
To declare a slot in your component's template, use the <slot></slot> tag:
class MyPanel : public Component<MyPanel> {
public:
std::string_view view = R"html(
<div class="panel-border">
<slot></slot>
</div>
)html";
};When using MyPanel inside a parent component, any children you nest inside <MyPanel> will automatically project into the <slot></slot> placeholder:
<MyPanel>
<p>This paragraph is projected inside the panel border.</p>
</MyPanel>Fallback Content
Content placed inside a slot declaration acts as its fallback: it is rendered when the caller projects no elements into that slot, and is replaced whenever projecting content is provided. If the projected content is dynamically unmounted (e.g. by a reactive <if> condition evaluating to false), the slot reverts to displaying its fallback markup:
<slot>
<span>Default placeholder content when no children are provided.</span>
</slot>Named Slots (<slot name="...">)
For complex components that have multiple customizable content zones (e.g. a Header, a Body, and a Footer), you can use named slots.
Declaring Named Slots
Give each slot a name attribute, as in HTML:
class PageLayout : public Component<PageLayout> {
public:
std::string_view view = R"html(
<div class="layout">
<div class="header-zone">
<slot name="header">Default Header Content</slot>
</div>
<div class="body-zone">
<slot></slot> <!-- Default slot for general content -->
</div>
<div class="footer-zone">
<slot name="footer"></slot>
</div>
</div>
)html";
};Projecting to Named Slots
When using a component with named slots, put a slot attribute on the element to project. To project several nodes, or text, without a wrapping element, put them in a <template slot="...">:
<PageLayout>
<!-- Projects to <slot name="header"> -->
<h1 slot="header">Welcome to my App</h1>
<!-- Projects to <slot> (default slot) -->
<p>Here is some page body content...</p>
<!-- Projects to <slot name="footer"> -->
<template slot="footer">Status: <b>Ready</b></template>
</PageLayout>Content naming the same slot fills it in the order it is written.
Selecting Projected Content by Tag (select)
slot="..." asks the consumer to say where content goes. Sometimes the component should decide instead, from the tag the consumer wrote. Give the slot a select attribute and it claims projected children with that tag, wherever they appear in the projected content:
<!-- Inside the component's own template -->
<div class="legend-line">
<slot name="legend" select="legend"></slot>
</div>
<div class="body">
<slot></slot>
</div><!-- What the consumer writes: no slot="legend" needed -->
<fieldset>
<legend>Group title</legend>
<div>body</div>
</fieldset>The <legend> is routed into the legend slot; everything else falls through to the default slot. This is how the built-in <fieldset> and <details> pick up <legend> and <summary>.
Selection looks through <if>, <elif>, <else> and <for>, so a conditionally rendered <legend> still reaches its slot, and the slot empties again when the condition turns off. Only elements are matched — bare text has no tag and always lands in the default slot.
Interactive Demo
Below is the live demo showcasing a reusable Card component using both named slots (for header and footer) and a default slot (for the body content):

