Slots
Slots define placeholders in layouts that are dynamically filled with templates. They are the foundation of layout composition. The slot wrapper element is completely replaced by the rendered template content — no wrapper div remains in the output.
---1. Basic Slot
Define a placeholder in your layout HTML:
<div data-slot="content"></div>
Fill it from CandidTemplate:
$tpl->slot('content', 'home');
Fill it from CandidTemplateAdaptor:
$view->slot('content', 'home');
---
2. Conditional Slot — slotIf()
Skips loading and rendering the slot entirely if the condition is false. The placeholder is also removed from the DOM — nothing is left in the output.
// Slot loads only if user is admin
$admin = $view->slotIf($user->isAdmin(), 'admin', 'admin-panel');
// Return value is nullable — use null-safe operator
$admin?->pick('username')->content($user->name);
Comparing showIf vs slotIf:
showIf() |
slotIf() |
|
|---|---|---|
| Template loaded | ✅ Always | ❌ Only if true |
| DOM removed | ✅ At render time | ✅ Immediately |
| File I/O saved | ❌ No | ✅ Yes |
| Return value | CandidElement | ?CandidTemplate |
3. Nested Slots
Sub-slots must be registered on the parent slot template, not on the root template. This makes the parent-child relationship explicit and avoids order-dependency issues.
// ✅ Correct — sub-slots registered on parent
$home = $view->slot('content', 'home');
$home->slot('slider', 'slider');
$home->slot('breaking', 'breaking');
$home->slot('featured', 'featured');
$home->slot('sidebar', 'sidebar');
// ❌ Wrong — sub-slots registered on root (order-dependent)
$view->slot('content', 'home');
$view->slot('slider', 'slider'); // fragile
$view->slot('breaking','breaking'); // fragile
Structure:
root → content (home)
├── slider
├── breaking
├── featured
└── sidebar
---
4. Slot with Data Binding
The slot return value gives direct access to pick and assign elements:
$navbar = $view->slot('navbar', 'navbar');
$navbar->pick('nav_home')->attribute('class', 'nav-item nav-link active');
$navbar->pick('nav_category')->attribute('class', 'nav-item nav-link');
$page = $view->slot('content', 'home');
$page->pick('title')->content('Welcome');
$page->pick('.hero-text')->content('Latest News');
---
5. Slot with Path
Optionally specify a subdirectory relative to the base path:
$tpl->slot('content', 'home', 'pages');
// resolves: basePath/pages/home.html
---
6. Slot Wrapper Removal
The data-slot wrapper element is completely removed after rendering.
Only the slot template content remains in the output.
// Layout
<div data-slot="topbar"></div>
// After render — wrapper gone, content inlined
<nav class="navbar">...</nav>
---
7. Common Mistakes
data-slot attribute in layout — slot silently skipped❌ Registering sub-slots on root instead of parent template
❌ Duplicate slot names in same layout
❌ Using
slotIf() return without null-safe operator (?->)❌ Wrong slot name — does not match
data-slot value
8. Rules
- Slot name must exactly match the
data-slotattribute value - Only the first matching
data-slotelement is used - The wrapper element is removed — only template content remains
- Sub-slots must be registered on the parent slot, not the root
slotIf()returns?CandidTemplate— always use null-safe operator- Slots registered via
CandidTemplateAdaptorautomatically resolve.data.phpfiles if present
9. Best Practices
- Use
slotIf()overshowIf()when entire sections are conditionally needed — avoids unnecessary file I/O - Register sub-slots explicitly on their parent template
- Keep slot hierarchy shallow — max 2 to 3 levels deep
- Use descriptive variable names for slot return values
- Avoid dynamic slot names — keep them static strings