Skip to content
Windwalker

Edge

Component
edge
A Blade compatible template engine with much extendable interface.

Layouts, Sections, and Stacks ​

Most pages share the same outer frame: a header, a navigation area, and a footer. Repeating that markup in every template makes changes slow and error-prone. Edge solves this with layout inheritance. A master layout defines the frame and named sections. Child templates extend the layout and fill those sections with their own content.

Stacks solve a related problem. A page body may need a script or stylesheet that belongs in the <head> or at the bottom of the layout. A child template can push content onto a named stack, and the layout prints the stack where it needs it.

Minimal Setup ​

A layout uses @yield to mark a place that children can fill. A child uses @extends to name its layout and @section to provide content:

blade
{{-- layouts/master.blade.php --}}
<html>
<head>
    <title>@yield('title', 'My Site')</title>
</head>
<body>
    @yield('content')
</body>
</html>
blade
{{-- pages/home.blade.php --}}
@extends('layouts.master')

@section('title', 'Home')

@section('content')
    <h1>Welcome</h1>
@endsection

Dots in layouts.master map to directories, as described in Loaders.

Showcase ​

The following example builds a page with a shared frame, a default sidebar, and a page-specific script. It renders end to end when the loader points at the directory that contains the layouts and pages folders:

php
$html = $edge->render('pages.dashboard', [
    'user' => ['name' => 'Simon'],
]);
blade
{{-- layouts/master.blade.php --}}
<html>
<head>
    <title>@yield('title', 'Admin')</title>
    @stack('scripts')
</head>
<body>
@section('sidebar')
    <nav>Default navigation</nav>
@show

<main>
    @yield('content')
</main>

@stack('bottom')
</body>
</html>
blade
{{-- pages/dashboard.blade.php --}}
@extends('layouts.master')

@section('title', 'Dashboard')

@section('sidebar')
    @parent
    <p>Signed in as {{ $user['name'] }}</p>
@endsection

@section('content')
    <h1>Dashboard</h1>
@endsection

@push('scripts')
    <script src="/js/dashboard.js"></script>
@endpush

The sidebar section is defined in the layout with @show. The child overrides it and calls @parent to keep the layout's default content before its own.

Sections ​

  • @section('name', 'value') sets a short section inline.
  • @section('name') opens a block that ends with @endsection or @stop.
  • @yield('name', 'default') prints a section in the layout. The second argument is shown when the child does not define the section.
  • @show defines a section in the layout and prints it immediately. Children can override it.
  • @parent inside a child section prints the parent's content for that section.

INFO

@show is the way to declare a section that has default content and can be extended. Use @yield when the layout only needs a slot that children must fill.

Stacks ​

Stacks collect content from many templates and print it once in the layout. A child pushes its scripts and styles, and the layout prints them in <head> or before </body>.

  • @push('name') and @endpush append a block to the stack.
  • @stack('name') prints the stack in the layout.
  • @pushIf($condition, 'name') pushes only when the condition is true.
  • @pushOnce('name', 'id') pushes a block once, even when the same template is rendered several times with the same id.
blade
@pushIf($user->isAdmin(), 'scripts')
    <script src="/js/admin.js"></script>
@endPushIf

Including Partials ​

@include renders another template at the current position. The included template receives the variables of the current template, and any array passed as the second argument overrides them:

blade
@include('partials.header', ['title' => 'Dashboard'])

@each renders a partial once for every item in an array. The partial receives the item under the name given as the third argument, and the array key under key:

blade
<ul>
    @each('partials.item', $items, 'item')
</ul>

@each accepts a fourth argument for an empty array. Use a template name, or prefix a plain string with raw|:

blade
@each('partials.item', $items, 'item', 'raw|No items.')

@hasSection checks whether a section has content, which lets a layout render a wrapper only when the child filled it:

blade
@hasSection('sidebar')
    <aside>@yield('sidebar')</aside>
@endif

Partials Rendered Once ​

Use @once for a block that should appear one time, such as a JavaScript library included by a reusable partial:

blade
@once('chart-library')
    @push('scripts')
        <script src="/js/chart.js"></script>
    @endpush
@endonce

The state for @once lives on the Edge instance. Each instance tracks its own set of ids, so a block is rendered once per instance, not once per request in a long-running process unless the same instance is reused.

TIP

Create the Edge instance once and reuse it. This keeps the compiled templates in the cache and keeps @once working across the partials rendered in one response.

Released under the MIT License.