How to use layout components in Livewire

Tuesday, 22nd December 2020

How to make an app layout component that can be used in your blade views and automatically used by full page Livewire components.

Setting up a layout component

Recently I converted my app to use blade components and one of the components I setup was for my app layout.

My original app layout file was stored at resources/views/layouts/app.blade.php and used @yield syntax (see Layouts Using Template Inheritance)

To make this a blade component, I moved the file to resources/views/components/layouts/app.blade.php and changed it to use the {{ $slot }} syntax (see Layouts Using Components).

This allowed me to wrap the contents of a blade view in an app layout tag like <x-layouts.app> instead of using @extends and @section tags.

<x-layouts.app>
<!-- content here -->
</x-layouts.app>

Now all my blade views can make use of that app layout component tag.

That layout component doesn’t work with Livewire (yet)

Out of the box, that app layout component won’t work with Livewire though.

When I started using Livewire, I saw that Livewire automatically uses the app layout file and populates {{ $slot }} for you (see Full Page Components).

That meant I didn’t need to wrap the contents of my full page Livewire component blade views with the app layout tag, as Livewire will handle that.

But for some reason that didn’t work. Nothing would load.

If you look closely at the full page components docs though, you will find that Livewire is actually looking for your app layout file in the old layouts location resources/views/layouts/app.blade.php, not in the components directory.

So Livewire can’t find find our newly created app layout component, as it’s looking in a different location.

To work around this, you have to resort to manually specifying it in your full page Livewire component’s render method, like this

public function render()
{
return view('livewire.sample-component')
->layout('components.layouts.app');
}

That’s painful though, as you have to specify this inside the render method of every full page Livewire component (trust me as I did this).

But there is another way.

The new app layout in the old app layout location

There is a technique you can use which makes use of a blade component class to point at a blade view file that is stored in a different location.

Take the new app layout component blade file, that uses the {{ $slot }} syntax, and move it back to the old location resources/views/layouts/app.blade.php, but keep the new syntax.

You can then create an inline blade component called Layouts/App

php artisan make:component Layouts/App --inline

Which generates this blade component php class (but no corresponding blade view)

app/View/Components/Layouts/App.php

Open up the newly create class and look at the render method, it will look something like this

public function render()
{
return <<<'blade'
<div>
<!-- An unexamined life is not worth living. - Socrates -->
</div>
blade;
}

Inside the render method, delete all the heredoc code (everything inside the render method) and instead you can return your app layout view (which we moved back out of the components directory earlier)

// app/View/Components/Layouts/App.php
public function render()
{
// Resolves to resources/views/layouts/app.blade.php
return view('layouts.app');
}

Now we are back to the way it was before, where you can use your app layout as component tags inside your standard blade views

<x-layouts.app>
<!-- content here -->
</x-layouts.app>

Livewire can now also find it in the correct location, so you don’t need to use the layout method inside your Livewire render method. So you render should look something like this

// Your Livewire component class
public function render()
{
// This auto finds the layout in resources/views/layouts/app.blade.php
return view('livewire.sample-component');
}

That’s all there is to setting up a layout component that can be used in blade templates and by full page Livewire components (without having to specify it each time).

Read on if you want to look at how to change the layout tag to a different name that Laravel Breeze and Jetstream both use.

A better layout tag name

Laravel Breeze and Jetstream both make use of <x-app-layout> as their layout tag.

It would be much nicer if we could actually use <x-app-layout> for the tag as I find it reads better than <x-layouts.app>. It also means we don’t have a component class file called App.php which could be confused with other app references.

If you prefer this, you can move the Layouts/App.php php class file that we generated earlier to the base components class directory and rename it

app/View/Components/AppLayout.php

Make sure you also open the file and change the class name to AppLayout.

Now your blade views can look like this

<x-app-layout>
<!-- content here -->
</x-app-layout>

And Livewire shouldn’t be impacted as we didn’t touch the app layout blade view.

This is how Laravel Breeze and Jetstream both handle this, see example in their respective GitHub repositories below.
breeze/AppLayout.php · GitHub
jetstream/AppLayout.php · GitHub

Update:
The second part to this has been published, check it out How to structure your layout file for Livewire.

Hope this helps!

Theme: Light - Dark - System