How to use Custom Slots in full page Livewire components

In this article I'll describe an undocumented, but very useful trick to use slots in Livewire.

Ralph J. Smit Laravel Software Engineer

If you are using full page components in Livewire, your component will look something like this:

class ShowPosts extends Component
{
...
public function render(): View
{
return view('livewire.show-posts')
->layout('layouts.base');
}
}

Then, your livewire.show-posts file contains the content of this component. The layouts.base file could look something like this (somewhat simplified):

<x-layouts.app>
<x-header />
 
<div>
<main>
{{ $slot }}
</main>
 
<x-sidebar>
<!-- Some hardcoded sidebar code -->
</x-sidebar>
 
<div>
<!-- Some other stuff -->
</div>
</div>
 
<x-footer />
</x-layouts.app>

This works very nicely. Livewire will automatically put the content of the livewire.show-posts file in the $slot variable and it will render the page.

But what if you would like to add some dynamic code in the sidebar? The code from Livewire will be passed into the $slot variable, so currently you cannot put some code in the <x-sidebar> component. In order to solve this, you could of course move the {{ $slot }} one level higher and put the complete code with <main>/<x-sidebar>/<div> in each Livewire component. However, that would be rather arduous, as that would mean that we would be rebuilding the sidebar and repeating the Some other stuff on every page.

Luckily, Laravel has a good solution for that: slots. Slots allow you to define code and that will be assigned to a different variable than $slot. It turns out that this also works with Livewire. Let's see how.

First, go to your layouts.base file and update it to use a variable called $sidebar:

@props([
'sidebar' => null,
])
 
<x-layouts.app>
<x-header />
 
<div>
<main>
{{ $slot }}
</main>
 
<x-sidebar>
<!-- Some hardcoded sidebar code -->
 
@if($sidebar)
{{ $sidebar }}
@endif
</x-sidebar>
 
<div>
<!-- Some other stuff -->
</div>
</div>
 
<x-footer />
</x-layouts.app>

Then, in your livewire.show-posts file, you can implement the sidebar slot:

<div>
<!-- Component code -->
</div>
 
<!-- The slot can be defined outside the Livewire root tag. -->
<x-slot:sidebar>
<!-- Sidebar code -->
</x-slot:sidebar>

Congrats! Reload the page and you should now see the sidebar code put in the sidebar, and main code put in the main page area.

Caveats

I think the above trick is very useful, but there's one downside to be aware of. That downside is that the code in the custom slots is static, so it will not be reloaded when you take actions on the Livewire page. Therefore, you should not include code that intends to do something with the Livewire component, like wire:click. (If you really need to use wire:click, you can use plain JavaScript and use the window.Livewire.call(). However, the code will not be refreshed.)

Therefore, it's good to keep in mind that this works fantastic for static pages. If you need to update the code in the slots, you could consider reloading the page by doing a redirect to the original route.

Happy coding!

Published by Ralph J. Smit on in Livewire . Last updated on 02 December 2023 .