Appearance
Blade style guide
This style guide applies to all .blade.php files. It covers how templates are split up and how data reaches them. For markup formatting, see the HTML style guide. For everything Blade itself can do, see the Laravel Blade documentation.
Template roles
Know which of these four you are writing before you start.
| Role | Lives in | Purpose |
|---|---|---|
| Page view | resources/views/<area>/ | Returned by a controller or Route::view(). Receives the data. |
| Layout | resources/views/mastertemplates/ or resources/views/components/layouts/ | The shared page chrome a page view renders inside. |
| Component | resources/views/components/ | Markup with an explicit data contract, also when only one page renders it. |
| Partial | a partials/ directory inside the area it belongs to | A chunk of one page view, pulled out for readability. A component does this job better. |
Two layout mechanisms are in use: most pages @extends('mastertemplates.…') and fill @sections, while the auth and error pages render inside a layout component (<x-layouts.auth>). Follow the mechanism the area already uses, and do not mix the two in one page.
Prefer components over includes
Use a component. That holds for markup you reuse, and it holds for a block you split off to keep one long page view readable.
@include is not banned, and the partials in the codebase are not there by mistake. A component is the better choice anyway: an include inherits every variable of the view that included it, so nothing states what the block needs, and renaming a variable in the parent breaks it without a word. A component receives what you pass it, and the call site says so.
blade
{{-- ✅ markup used in several places --}}
<x-html.card :title="__('video.title')">
…
</x-html.card>
{{-- ✅ one page split for readability, still a component --}}
<x-enrich.editor.top-section :embedded="$embedded"
:video="$video"/>
{{-- allowed, but not preferred --}}
@include('livewire.video.editor.partials.selectable-content')
{{-- ❌ reusable markup as an include --}}
@include('partials.card', ['title' => __('video.title')])Component syntax
Write components with the <x-name> tag syntax. Never use @component. Laravel 6 was the last release whose documentation still described it.
blade
{{-- ✅ --}}
<x-settings.row for="title"
:label="__('video.title')"/>
{{-- ❌ --}}
@component('settings.row', ['label' => __('video.title')])
@endcomponentCreate components with Artisan, so they land in the right place:
php artisan make:component --view <name>for an anonymous component, a Blade file only.php artisan make:component <name>for a class component, a Blade file plus a class.
Default to anonymous components. Use a class component only when rendering needs logic that markup cannot express: dependency injection, a computed collection, or a decision that would otherwise become a pile of @ifs in the template.
Props
Declare every prop in a multi-line @props block with a /** @var Type */ docblock. Blade files have no use imports, so write the fully qualified class name.
A key without a default is required. Give an optional prop a default, so its type and its declaration agree.
blade
@props([
/** @var \App\Models\Video */
'video',
/** @var string|null */
'label' => null,
])Pass data with an attribute binding (:video="$video"), and pass markup with a named slot (<x-slot:footer>). Both keep the contract visible at the call site.
Data comes from the controller
A Blade file displays data. It does not fetch or change it. Query the database, call actions and shape the result in the controller, then pass it to the view.
blade
{{-- ❌ a query in a template: an N+1 waiting to happen, and untestable --}}
@foreach($container->videos()->latest()->get() as $video)@php is allowed, and useful, for:
- Declaring the types of the variables the template received.
- Importing a class or enum the template references, since Blade has no
usestatements of its own. - A small, presentation-only derivation that has no meaning outside this template.
blade
@php
use App\Enums\PortalPdfState;
/** @var \App\Models\Video $video */
@endphpImports come first, as they do in a PHP file. With the import in place the docblock can use the short class name. @props blocks have no imports of their own, so those keep the fully qualified name.
Anything longer than a few lines, or anything another template would also want, belongs in PHP: a model accessor, a resource, or an App\View\Elements class.
Formatting
Indent with four spaces.
blade
<a href="/open-source">
Open Source
</a>Write a directive and its opening bracket as one word.
blade
{{-- ✅ --}}
@if($condition)
Something
@endif
{{-- ❌ --}}
@if ($condition)
Something
@endifThe same goes for @foreach, @forelse, @unless, @isset, @include and every other directive that takes an argument.
The PHP inside the brackets keeps its own spacing. A unary not still takes a space after it, as it does in a PHP file, because Pint does not format Blade templates.
blade
{{-- ✅ --}}
@if(! $video->isPublished())
{{-- ❌ --}}
@if(!$video->isPublished())Attribute and child-element formatting follows the HTML style guide. File and directory names follow the view naming rules.