HLCRF Deep Dive
This guide provides an in-depth look at the HLCRF (Header-Left-Content-Right-Footer) layout system, covering all layout combinations, the ID system, responsive patterns, and complex real-world examples.
Layout Combinations
HLCRF supports any combination of its five regions. The variant name describes which regions are present.
All Possible Combinations
| Variant | Regions | Use Case |
|---|---|---|
C | Content only | Simple content pages |
HC | Header + Content | Landing pages |
CF | Content + Footer | Article pages |
HCF | Header + Content + Footer | Standard pages |
LC | Left + Content | App with navigation |
CR | Content + Right | Content with sidebar |
LCR | Left + Content + Right | Three-column layout |
HLC | Header + Left + Content | Admin dashboard |
HCR | Header + Content + Right | Blog with widgets |
LCF | Left + Content + Footer | App with footer |
CRF | Content + Right + Footer | Blog layout |
HLCF | Header + Left + Content + Footer | Standard admin |
HCRF | Header + Content + Right + Footer | Blog layout |
HLCR | Header + Left + Content + Right | Full admin |
LCRF | Left + Content + Right + Footer | Complex app |
HLCRF | All five regions | Complete layout |
Content-Only (C)
Minimal layout for simple content:
use Core\Front\Components\Layout;
$layout = Layout::make('C')
->c('<main>Simple content without chrome</main>');
echo $layout->render();Output:
<div class="hlcrf-layout" data-layout="root">
<div class="hlcrf-body flex flex-1">
<main class="hlcrf-content flex-1" data-slot="C">
<div data-block="C-0">
<main>Simple content without chrome</main>
</div>
</main>
</div>
</div>Header + Content + Footer (HCF)
Standard page layout:
$layout = Layout::make('HCF')
->h('<nav>Site Navigation</nav>')
->c('<article>Page Content</article>')
->f('<footer>Copyright 2026</footer>');Left + Content (LC)
Application with navigation sidebar:
$layout = Layout::make('LC')
->l('<nav class="w-64">App Menu</nav>')
->c('<main>App Content</main>');Three-Column (LCR)
Full three-column layout:
$layout = Layout::make('LCR')
->l('<nav>Navigation</nav>')
->c('<main>Content</main>')
->r('<aside>Widgets</aside>');Full Admin (HLCRF)
Complete admin panel:
$layout = Layout::make('HLCRF')
->h('<header>Admin Header</header>')
->l('<nav>Sidebar</nav>')
->c('<main>Dashboard</main>')
->r('<aside>Quick Actions</aside>')
->f('<footer>Status Bar</footer>');The ID System
Every HLCRF element receives a unique, hierarchical ID that describes its position in the layout tree.
ID Format
{Region}-{Index}[-{NestedRegion}-{NestedIndex}]...Components:
- Region Letter -
H,L,C,R, orF - Index - Zero-based position within that slot (0, 1, 2, ...)
- Nesting - Dash-separated chain for nested layouts
Region Letters
| Letter | Region | Semantic Role |
|---|---|---|
H | Header | Top navigation, branding |
L | Left | Primary sidebar, navigation |
C | Content | Main content area |
R | Right | Secondary sidebar, widgets |
F | Footer | Bottom links, copyright |
ID Examples
Simple layout:
<div data-layout="root">
<header data-slot="H">
<div data-block="H-0">First header element</div>
<div data-block="H-1">Second header element</div>
</header>
<main data-slot="C">
<div data-block="C-0">First content element</div>
</main>
</div>Nested layout:
<div data-layout="root">
<main data-slot="C">
<div data-block="C-0">
<!-- Nested layout inside content -->
<div data-layout="C-0-">
<aside data-slot="C-0-L">
<div data-block="C-0-L-0">Nested left sidebar</div>
</aside>
<main data-slot="C-0-C">
<div data-block="C-0-C-0">Nested content</div>
</main>
</div>
</div>
</main>
</div>ID Interpretation
| ID | Meaning |
|---|---|
H-0 | First element in Header |
L-2 | Third element in Left sidebar |
C-0 | First element in Content |
C-L-0 | Content > Left > First element |
C-R-2 | Content > Right > Third element |
C-L-0-R-1 | Content > Left > First > Right > Second |
H-0-C-0-L-0 | Header > Content > Left (deeply nested) |
Using IDs for CSS
The ID system enables precise CSS targeting:
/* Target first header element */
[data-block="H-0"] {
background: #1a1a2e;
}
/* Target all elements in left sidebar */
[data-slot="L"] > [data-block] {
padding: 1rem;
}
/* Target nested content areas */
[data-block*="-C-"] {
margin: 2rem;
}
/* Target second element in any right sidebar */
[data-block$="-R-1"] {
border-top: 1px solid #e5e7eb;
}
/* Target deeply nested layouts */
[data-layout*="-"][data-layout*="-"] {
background: #f9fafb;
}Using IDs for Testing
// PHPUnit/Pest
$this->assertSee('[data-block="H-0"]');
$this->assertSeeInOrder(['[data-slot="L"]', '[data-slot="C"]']);
// Playwright/Cypress
await page.locator('[data-block="C-0"]').click();
await expect(page.locator('[data-slot="R"]')).toBeVisible();Using IDs for JavaScript
// Target specific elements
const header = document.querySelector('[data-block="H-0"]');
const sidebar = document.querySelector('[data-slot="L"]');
// Dynamic targeting
function getContentBlock(index) {
return document.querySelector(`[data-block="C-${index}"]`);
}
// Nested targeting
const nestedLeft = document.querySelector('[data-block="C-L-0"]');Responsive Design Patterns
Mobile-First Stacking
On mobile, stack regions vertically:
<x-hlcrf::layout
:breakpoints="[
'mobile' => 'stack',
'tablet' => 'LC',
'desktop' => 'LCR',
]"
>
<x-hlcrf::left>Navigation</x-hlcrf::left>
<x-hlcrf::content>Content</x-hlcrf::content>
<x-hlcrf::right>Widgets</x-hlcrf::right>
</x-hlcrf::layout>Behavior:
- Mobile (< 768px): Left -> Content -> Right (vertical)
- Tablet (768px-1024px): Left | Content (two columns)
- Desktop (> 1024px): Left | Content | Right (three columns)
Collapsible Sidebars
<x-hlcrf::left
collapsible="true"
collapsed-width="64px"
expanded-width="256px"
:collapsed="$sidebarCollapsed"
>
<div class="sidebar-content">
@if(!$sidebarCollapsed)
<span>Full navigation content</span>
@else
<span>Icons only</span>
@endif
</div>
</x-hlcrf::left>Hidden Regions on Mobile
<x-hlcrf::right
class="hidden md:block"
width="300px"
>
{{-- Only visible on medium screens and up --}}
<x-widget-panel />
</x-hlcrf::right>Flexible Width Distribution
<x-hlcrf::layout>
<x-hlcrf::left width="250px" class="shrink-0">
Fixed-width sidebar
</x-hlcrf::left>
<x-hlcrf::content class="flex-1 min-w-0">
Flexible content
</x-hlcrf::content>
<x-hlcrf::right width="25%" class="shrink-0">
Percentage-width sidebar
</x-hlcrf::right>
</x-hlcrf::layout>Responsive Grid Inside Content
<x-hlcrf::content>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<x-stat-card title="Users" :value="$userCount" />
<x-stat-card title="Posts" :value="$postCount" />
<x-stat-card title="Comments" :value="$commentCount" />
</div>
</x-hlcrf::content>Complex Real-World Examples
Admin Dashboard
A complete admin dashboard with nested layouts:
use Core\Front\Components\Layout;
// Main admin layout
$admin = Layout::make('HLCF')
->h(
'<nav class="flex items-center justify-between px-4 py-2 bg-gray-900 text-white">
<div class="logo">Admin Panel</div>
<div class="user-menu">
<span>user@example.com</span>
</div>
</nav>'
)
->l(
'<nav class="w-64 bg-gray-800 text-gray-300 min-h-screen p-4">
<a href="/dashboard" class="block py-2">Dashboard</a>
<a href="/users" class="block py-2">Users</a>
<a href="/settings" class="block py-2">Settings</a>
</nav>'
)
->c(
// Nested layout inside content
Layout::make('HCR')
->h('<div class="flex items-center justify-between p-4 border-b">
<h1 class="text-xl font-semibold">Dashboard</h1>
<button class="btn-primary">New Item</button>
</div>')
->c('<div class="p-6">
<div class="grid grid-cols-3 gap-4 mb-6">
<div class="bg-white p-4 rounded shadow">Stat 1</div>
<div class="bg-white p-4 rounded shadow">Stat 2</div>
<div class="bg-white p-4 rounded shadow">Stat 3</div>
</div>
<div class="bg-white p-4 rounded shadow">
<h2 class="font-medium mb-4">Recent Activity</h2>
<table class="w-full">...</table>
</div>
</div>')
->r('<aside class="w-80 p-4 bg-gray-50 border-l">
<h3 class="font-medium mb-4">Quick Actions</h3>
<div class="space-y-2">
<button class="w-full btn-secondary">Export Data</button>
<button class="w-full btn-secondary">Generate Report</button>
</div>
</aside>')
)
->f(
'<footer class="px-4 py-2 bg-gray-100 text-gray-600 text-sm">
Version 1.0.0 | Last sync: 5 minutes ago
</footer>'
);
echo $admin->render();Generated IDs:
H-0- Admin header/navigationL-0- Sidebar navigationC-0- Nested layout containerC-0-H-0- Content header (page title/actions)C-0-C-0- Content main area (stats/table)C-0-R-0- Content right sidebar (quick actions)F-0- Admin footer
E-Commerce Product Page
Product page with nested sections:
$productPage = Layout::make('HCF')
->h('<header class="border-b">
<nav>Store Navigation</nav>
<div>Search | Cart | Account</div>
</header>')
->c(
Layout::make('LCR')
->l('<div class="w-1/2">
<div class="aspect-square bg-gray-100">
<img src="/product-main.jpg" alt="Product" />
</div>
<div class="flex gap-2 mt-4">
<img src="/thumb-1.jpg" class="w-16 h-16" />
<img src="/thumb-2.jpg" class="w-16 h-16" />
</div>
</div>')
->c(
// Empty - using left/right only
)
->r('<div class="w-1/2 p-6">
<h1 class="text-2xl font-bold">Product Name</h1>
<p class="text-xl text-green-600 mt-2">$99.99</p>
<p class="mt-4">Product description...</p>
<div class="mt-6 space-y-4">
<select>Size options</select>
<button class="w-full btn-primary">Add to Cart</button>
</div>
<div class="mt-6 border-t pt-4">
<h3>Shipping Info</h3>
<p>Free delivery over $50</p>
</div>
</div>'),
// Reviews section
Layout::make('CR')
->c('<div class="p-6">
<h2 class="text-xl font-bold mb-4">Customer Reviews</h2>
<div class="space-y-4">
<div class="border-b pb-4">Review 1...</div>
<div class="border-b pb-4">Review 2...</div>
</div>
</div>')
->r('<aside class="w-64 p-4 bg-gray-50">
<h3>You May Also Like</h3>
<div class="space-y-2">
<div>Related Product 1</div>
<div>Related Product 2</div>
</div>
</aside>')
)
->f('<footer class="bg-gray-900 text-white p-8">
<div class="grid grid-cols-4 gap-8">
<div>About Us</div>
<div>Customer Service</div>
<div>Policies</div>
<div>Newsletter</div>
</div>
</footer>');Multi-Panel Settings Page
Settings page with multiple nested panels:
$settings = Layout::make('HLC')
->h('<header class="border-b p-4">
<h1>Account Settings</h1>
</header>')
->l('<nav class="w-48 border-r">
<a href="#profile" class="block p-3 bg-blue-50">Profile</a>
<a href="#security" class="block p-3">Security</a>
<a href="#notifications" class="block p-3">Notifications</a>
<a href="#billing" class="block p-3">Billing</a>
</nav>')
->c(
// Profile section
Layout::make('HCF')
->h('<div class="p-4 border-b">
<h2 class="font-semibold">Profile Information</h2>
<p class="text-gray-600 text-sm">Update your account details</p>
</div>')
->c('<form class="p-6 space-y-4">
<div>
<label>Name</label>
<input type="text" value="John Doe" />
</div>
<div>
<label>Email</label>
<input type="email" value="john@example.com" />
</div>
<div>
<label>Bio</label>
<textarea rows="4"></textarea>
</div>
</form>')
->f('<div class="p-4 border-t bg-gray-50 flex justify-end gap-2">
<button class="btn-secondary">Cancel</button>
<button class="btn-primary">Save Changes</button>
</div>')
);Documentation Site
Documentation layout with table of contents:
$docs = Layout::make('HLCRF')
->h('<header class="border-b">
<div class="flex items-center justify-between px-6 py-3">
<div class="flex items-center gap-4">
<img src="/logo.svg" class="h-8" />
<nav class="hidden md:flex gap-6">
<a href="/docs">Docs</a>
<a href="/api">API</a>
<a href="/examples">Examples</a>
</nav>
</div>
<div class="flex items-center gap-4">
<input type="search" placeholder="Search..." />
<a href="/github">GitHub</a>
</div>
</div>
</header>')
->l('<nav class="w-64 p-4 border-r overflow-y-auto">
<h4 class="font-semibold text-gray-500 uppercase text-xs mb-2">Getting Started</h4>
<a href="/docs/intro" class="block py-1 text-blue-600">Introduction</a>
<a href="/docs/install" class="block py-1">Installation</a>
<a href="/docs/quick-start" class="block py-1">Quick Start</a>
<h4 class="font-semibold text-gray-500 uppercase text-xs mt-6 mb-2">Core Concepts</h4>
<a href="/docs/layouts" class="block py-1">Layouts</a>
<a href="/docs/components" class="block py-1">Components</a>
<a href="/docs/routing" class="block py-1">Routing</a>
</nav>')
->c('<article class="prose max-w-3xl mx-auto p-8">
<h1>Introduction</h1>
<p>Welcome to the documentation...</p>
<h2>Key Features</h2>
<ul>
<li>Feature 1</li>
<li>Feature 2</li>
<li>Feature 3</li>
</ul>
<h2>Next Steps</h2>
<p>Continue to the installation guide...</p>
</article>')
->r('<aside class="w-48 p-4 border-l">
<h4 class="font-semibold text-sm mb-2">On This Page</h4>
<nav class="text-sm space-y-1">
<a href="#intro" class="block text-gray-600">Introduction</a>
<a href="#features" class="block text-gray-600">Key Features</a>
<a href="#next" class="block text-gray-600">Next Steps</a>
</nav>
</aside>')
->f('<footer class="border-t p-4 flex justify-between text-sm text-gray-600">
<div>
<a href="/prev" class="text-blue-600">← Previous: Setup</a>
</div>
<div>
<a href="/next" class="text-blue-600">Next: Installation →</a>
</div>
</footer>');Email Client Interface
Complex email client with multiple nested panels:
$email = Layout::make('HLCR')
->h('<header class="bg-white border-b px-4 py-2 flex items-center justify-between">
<div class="flex items-center gap-4">
<button class="btn-icon">Menu</button>
<img src="/logo.svg" class="h-6" />
</div>
<div class="flex-1 max-w-2xl mx-4">
<input type="search" placeholder="Search mail" class="w-full" />
</div>
<div class="flex items-center gap-2">
<button class="btn-icon">Settings</button>
<div class="avatar">JD</div>
</div>
</header>')
->l('<aside class="w-64 border-r flex flex-col">
<div class="p-3">
<button class="w-full btn-primary">Compose</button>
</div>
<nav class="flex-1 overflow-y-auto">
<a href="#inbox" class="flex items-center gap-3 px-4 py-2 bg-blue-50">
<span class="icon">inbox</span>
<span class="flex-1">Inbox</span>
<span class="badge">12</span>
</a>
<a href="#starred" class="flex items-center gap-3 px-4 py-2">
<span class="icon">star</span>
<span>Starred</span>
</a>
<a href="#sent" class="flex items-center gap-3 px-4 py-2">
<span class="icon">send</span>
<span>Sent</span>
</a>
<a href="#drafts" class="flex items-center gap-3 px-4 py-2">
<span class="icon">draft</span>
<span>Drafts</span>
</a>
</nav>
<div class="p-4 border-t text-sm text-gray-600">
Storage: 2.4 GB / 15 GB
</div>
</aside>')
->c(
Layout::make('LC')
->l('<div class="w-80 border-r overflow-y-auto">
<div class="p-2 border-b">
<select class="w-full text-sm">
<option>All Mail</option>
<option>Unread</option>
<option>Starred</option>
</select>
</div>
<div class="divide-y">
<div class="p-3 bg-blue-50 cursor-pointer">
<div class="flex items-center justify-between">
<span class="font-medium">John Smith</span>
<span class="text-xs text-gray-500">10:30 AM</span>
</div>
<div class="font-medium text-sm">Meeting Tomorrow</div>
<div class="text-sm text-gray-600 truncate">Hi, just wanted to confirm...</div>
</div>
<div class="p-3 cursor-pointer">
<div class="flex items-center justify-between">
<span class="font-medium">Jane Doe</span>
<span class="text-xs text-gray-500">Yesterday</span>
</div>
<div class="font-medium text-sm">Project Update</div>
<div class="text-sm text-gray-600 truncate">Here is the latest update...</div>
</div>
</div>
</div>')
->c('<div class="flex-1 flex flex-col">
<div class="p-4 border-b flex items-center gap-2">
<button class="btn-icon">Archive</button>
<button class="btn-icon">Delete</button>
<button class="btn-icon">Move</button>
<span class="border-l h-6 mx-2"></span>
<button class="btn-icon">Reply</button>
<button class="btn-icon">Forward</button>
</div>
<div class="flex-1 overflow-y-auto p-6">
<div class="mb-6">
<h2 class="text-xl font-medium">Meeting Tomorrow</h2>
<div class="flex items-center gap-3 mt-2 text-sm text-gray-600">
<div class="avatar">JS</div>
<div>
<div>John Smith <john@example.com></div>
<div>to me</div>
</div>
<div class="ml-auto">Jan 15, 2026, 10:30 AM</div>
</div>
</div>
<div class="prose">
<p>Hi,</p>
<p>Just wanted to confirm our meeting tomorrow at 2pm.</p>
<p>Best regards,<br>John</p>
</div>
</div>
</div>')
)
->r('<aside class="w-64 border-l p-4 hidden xl:block">
<h3 class="font-medium mb-4">Contact Info</h3>
<div class="text-sm space-y-2">
<div>John Smith</div>
<div class="text-gray-600">john@example.com</div>
<div class="text-gray-600">+1 555 123 4567</div>
</div>
<h3 class="font-medium mt-6 mb-4">Related Emails</h3>
<div class="text-sm space-y-2">
<a href="#" class="block text-blue-600">Re: Project Timeline</a>
<a href="#" class="block text-blue-600">Meeting Notes</a>
</div>
</aside>');Performance Considerations
Lazy Content Loading
For large layouts, defer non-critical content:
$layout = Layout::make('LCR')
->l('<nav>Immediate navigation</nav>')
->c('<main wire:init="loadContent">
<div wire:loading>Loading...</div>
<div wire:loading.remove>@livewire("content-panel")</div>
</main>')
->r(fn () => view('widgets.sidebar')); // Closure defers evaluationConditional Region Rendering
Only render regions when needed:
$layout = Layout::make('LCR');
$layout->l('<nav>Navigation</nav>');
$layout->c('<main>Content</main>');
// Conditionally add right sidebar
if ($user->hasFeature('widgets')) {
$layout->r('<aside>Widgets</aside>');
}Efficient CSS Targeting
Use data attributes instead of deep selectors:
/* Efficient - uses data attribute */
[data-block="C-0"] { padding: 1rem; }
/* Less efficient - deep selector */
.hlcrf-layout > .hlcrf-body > .hlcrf-content > div:first-child { padding: 1rem; }Testing HLCRF Layouts
Unit Testing
use Core\Front\Components\Layout;
use PHPUnit\Framework\TestCase;
class LayoutTest extends TestCase
{
public function test_generates_correct_ids(): void
{
$layout = Layout::make('LC')
->l('Left')
->c('Content');
$html = $layout->render();
$this->assertStringContainsString('data-slot="L"', $html);
$this->assertStringContainsString('data-slot="C"', $html);
$this->assertStringContainsString('data-block="L-0"', $html);
$this->assertStringContainsString('data-block="C-0"', $html);
}
public function test_nested_layout_ids(): void
{
$nested = Layout::make('LR')
->l('Nested Left')
->r('Nested Right');
$outer = Layout::make('C')
->c($nested);
$html = $outer->render();
$this->assertStringContainsString('data-block="C-0-L-0"', $html);
$this->assertStringContainsString('data-block="C-0-R-0"', $html);
}
}Browser Testing
// Pest with Playwright
it('renders admin layout correctly', function () {
$this->browse(function ($browser) {
$browser->visit('/admin')
->assertPresent('[data-layout="root"]')
->assertPresent('[data-slot="H"]')
->assertPresent('[data-slot="L"]')
->assertPresent('[data-slot="C"]');
});
});Best Practices
1. Use Semantic Region Names
// Good - semantic use
->h('<nav>Global navigation</nav>')
->l('<nav>Page navigation</nav>')
->c('<main>Page content</main>')
->r('<aside>Related content</aside>')
->f('<footer>Site footer</footer>')
// Bad - misuse of regions
->h('<aside>Sidebar content</aside>') // Header for sidebar?2. Leverage the ID System
/* Target specific elements precisely */
[data-block="H-0"] { /* Header first element */ }
[data-block="C-L-0"] { /* Content > Left > First */ }
/* Don't fight the system with complex selectors */3. Keep Nesting Shallow
// Good - 2-3 levels max
Layout::make('HCF')
->c(Layout::make('LCR')->...);
// Avoid - too deep
Layout::make('C')
->c(Layout::make('C')
->c(Layout::make('C')
->c(Layout::make('C')...))));4. Use Consistent Widths
// Good - consistent sidebar widths across app
->l('<nav class="w-64">') // Always 256px
->r('<aside class="w-80">') // Always 320px5. Handle Empty Regions Gracefully
// Regions without content don't render
$layout = Layout::make('LCR')
->l('<nav>Nav</nav>')
->c('<main>Content</main>');
// No ->r() call - right sidebar won't render