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

❌ Missing 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

---

9. Best Practices

---
Slots are the backbone of layout composition. The wrapper element is always removed — your rendered HTML stays clean with no leftover placeholder divs.