Courses

Livewire 3 From Scratch: Practical Course

Full-page Components to Replace Laravel Controllers

Summary of this lesson:
- Setting up routes for Livewire components
- Configuring layouts for components
- Managing page titles
- Using component-specific layouts

In general, there are two main ways to use Livewire:

  • You build the full project with Laravel Controllers, and use Livewire only for small dynamic elements on the pages
  • You use Livewire Components instead of Laravel Controllers, with so-called Full-Page Components

The choice is yours, it's a personal preference. In this lesson, let's see how to do it with full-page components.


Routes

Instead of mapping to the Controller in the Routes files, you just need to map directly to the Livewire component.

use App\Livewire\CreatePost;
 
Route::get('/posts/create', CreatePost::class);

Layout Files

Livewire uses Blade component as an application layout. So it needs to have a {{ $slot }} placeholder. By default, Livewire uses the resources/views/components/layouts/app.blade.php Blade file for the main layout.

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
 
<title>{{ $title ?? 'Page Title' }}</title>
</head>
<body>
{{ $slot }}
</body>
</html>

The main layout's location can be changed in two ways: global and per-component.

Global Layout Configuration

To use the same layout for all components, you can set layout in the config/livewire.php to the path where your layout is.

config/livewire.php:

// ...
 
'layout' => 'layouts.app',
 
// ...

Per-component Layout Configuration

To set the layout for a particular component, you must use the #[Layout] attribute either above the render method or the class declaration.

use Livewire\Attributes\Layout;
use Livewire\Component;
 
#[Layout('layouts.app')]
class CreatePost extends Component
{
// ...
 
#[Layout('layouts.app')]
public function render()
{
return view('livewire.create-post');
}
}

Or you can have a base Livewire component to set the layout. For example, the layout could be different for the admin. Then, in one Livewire component, you would set the layout.

#[Layout('components.layouts.admin)]
class AdminComponent extends \Livewire\Component {}

And all other Livewire components should then extend this AdminComponent instead of a \Livewire\Component.

class AdminPanel extends AdminComponent {}

Setting Page Title

Setting a unique title for the page is very useful. First, you need to have a $title variable in the layouts title section.

<head>
<title>{{ $title ?? 'Page Title' }}</title>
</head>

Next, similar to how you can set the layout per-component using attributes, you can set the title by adding the #[Title] attribute.

use Livewire\Attributes\Title;
use Livewire\Component;
 
class CreatePost extends Component
{
// ...
 
#[Title('Create Post')]
public function render()
{
return view('livewire.create-post');
}
}

If you need a dynamic title, use the title method in the component's render method.

class CreatePost extends Component
{
// ...
 
public function render()
{
return view('livewire.create-post')
->title('Create Post');
}
}

And that's it: you don't need Laravel Controllers then, all your Routes may lead to full-page Livewire components.

Previous: Hooks: updated() and updatedField()
avatar

If we are using resources/views/components/layouts/app.blade.php as global layout

then the config/livewire.php should read

'layout' => 'components/layouts.app',
avatar

Yes, but you don't necessarily have to have this config, as it is the DEFAULT value.

Quote from the docs: "By default, Livewire will automatically look for a layout file named: resources/views/components/layouts/app.blade.php"

avatar

I’m sorry but in my version Laravel/framework 10.35.0 and laravel/breeze 1.26.2 with livewire/livewire 3.3.0 Out of the box Laravel puts the layouts in its one directory. Resources/views/layouts/app.blade.php

Not in resources/views/components/layouts/app.blade.php.

However if you create a new layout using the php artisan make:component AppLayout command it will put the file in the components directory but not in a layouts subdirectory in less you tell it to.

PS. under the latest “Laravel new” you can get Breeze to setup using livewire 3 and the old problems with Alpin.js has been taken care of.

avatar

I have the same issue! My app layout is in 'resources/views/layouts/app.blade.php' - What was your workaround for this, Richard? Did you just update the livewire config file to use layouts.app.blade?

avatar

Please read the docs about layouts https://livewire.laravel.com/docs/components#layout-files

avatar
You can use Markdown
avatar

What is the differnce between mapping directly to the Livewire component like the above example and doing this?

Route::view('/posts/create', 'admin.posts.create');

And then in the 'admin.posts.create' render the posts component?

'<x-app-layout>'<livewire:create-post /></x-app-layout>

The only thing that I can see is that we avoid having an extra file that only renders the component

avatar

Using directly component it's called a full page component. Not everyone likes them and not always it's needed. Livewire can be used just in some parts of the page, for example only for comments on the page, or for like/dislike button. But it's more a personal preference.

avatar

Got it! And in case that I want to use the index method for the post, is it possible to do it with livewire if we are using it already? I want to avoid having a PostController only for the index method

avatar

You can fully use full page Livewire components. In the routes instead of calling controller call the Livewire component. In your case you can name it for example PostsIndex.

avatar
You can use Markdown
avatar
You can use Markdown