Skip to content

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

VariantRegionsUse Case
CContent onlySimple content pages
HCHeader + ContentLanding pages
CFContent + FooterArticle pages
HCFHeader + Content + FooterStandard pages
LCLeft + ContentApp with navigation
CRContent + RightContent with sidebar
LCRLeft + Content + RightThree-column layout
HLCHeader + Left + ContentAdmin dashboard
HCRHeader + Content + RightBlog with widgets
LCFLeft + Content + FooterApp with footer
CRFContent + Right + FooterBlog layout
HLCFHeader + Left + Content + FooterStandard admin
HCRFHeader + Content + Right + FooterBlog layout
HLCRHeader + Left + Content + RightFull admin
LCRFLeft + Content + Right + FooterComplex app
HLCRFAll five regionsComplete layout

Content-Only (C)

Minimal layout for simple content:

php
use Core\Front\Components\Layout;

$layout = Layout::make('C')
    ->c('<main>Simple content without chrome</main>');

echo $layout->render();

Output:

html
<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>

Standard page layout:

php
$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:

php
$layout = Layout::make('LC')
    ->l('<nav class="w-64">App Menu</nav>')
    ->c('<main>App Content</main>');

Three-Column (LCR)

Full three-column layout:

php
$layout = Layout::make('LCR')
    ->l('<nav>Navigation</nav>')
    ->c('<main>Content</main>')
    ->r('<aside>Widgets</aside>');

Full Admin (HLCRF)

Complete admin panel:

php
$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, or F
  • Index - Zero-based position within that slot (0, 1, 2, ...)
  • Nesting - Dash-separated chain for nested layouts

Region Letters

LetterRegionSemantic Role
HHeaderTop navigation, branding
LLeftPrimary sidebar, navigation
CContentMain content area
RRightSecondary sidebar, widgets
FFooterBottom links, copyright

ID Examples

Simple layout:

html
<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:

html
<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

IDMeaning
H-0First element in Header
L-2Third element in Left sidebar
C-0First element in Content
C-L-0Content > Left > First element
C-R-2Content > Right > Third element
C-L-0-R-1Content > Left > First > Right > Second
H-0-C-0-L-0Header > Content > Left (deeply nested)

Using IDs for CSS

The ID system enables precise CSS targeting:

css
/* 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

php
// 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

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:

blade
<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

blade
<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

blade
<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

blade
<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

blade
<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:

php
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/navigation
  • L-0 - Sidebar navigation
  • C-0 - Nested layout container
  • C-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:

php
$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:

php
$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:

php
$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">&larr; Previous: Setup</a>
        </div>
        <div>
            <a href="/next" class="text-blue-600">Next: Installation &rarr;</a>
        </div>
    </footer>');

Email Client Interface

Complex email client with multiple nested panels:

php
$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 &lt;john@example.com&gt;</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:

php
$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 evaluation

Conditional Region Rendering

Only render regions when needed:

php
$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:

css
/* 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

php
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

php
// 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

php
// 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

css
/* 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

php
// 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

php
// Good - consistent sidebar widths across app
->l('<nav class="w-64">')  // Always 256px
->r('<aside class="w-80">') // Always 320px

5. Handle Empty Regions Gracefully

php
// 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

Learn More

Released under the EUPL-1.2 License.