Livewire components are essentially PHP classes with properties and methods that can be called directly from a Blade template. This powerful combination allows you to create full-stack interactive interfaces with a fraction of the effort and complexity of modern JavaScript alternatives.
This guide covers everything you need to know about creating, rendering, and organizing Livewire components. You'll learn about the different component formats available (single-file, multi-file, and class-based), how to pass data between components, and how to use components as full pages.
You can create a component using the make:livewire Artisan command:
php artisan make:livewire post.createThis creates a single-file component at:
resources/views/components/post/⚡create.blade.php
<?php
use Livewire\Component;
new class extends Component {
public $title = '';
public function save()
{
// Save logic here...
}
};
?>
<div>
<input wire:model="title" type="text">
<button wire:click="save">Save Post</button>
</div>[!info] Why the ⚡ emoji? You might be wondering about the lightning bolt in the filename. This small touch serves a practical purpose: it makes Livewire components instantly recognizable in your editor's file tree and search results. Since it's a Unicode character, it works seamlessly across all platforms — Windows, macOS, Linux, Git, and your production servers. The emoji is completely optional and if you find it outside your comfort zone you can disable it entirely in yourconfig/livewire.phpfile: ``php 'make_command' => [ 'emoji' => false, ],``
[!tip] Prefer v3 conventions? If you prefer class-based components from v3, you can restore the previous defaults with two config lines inconfig/livewire.php: ``php 'make_command' => [ 'type' => 'class', 'emoji' => false, ],``
When creating components that will be used as full pages, use the pages:: namespace to organize them in a dedicated directory:
php artisan make:livewire pages::post.createThis creates the component at resources/views/pages/post/⚡create.blade.php. This organization makes it clear which components are pages versus reusable UI components.
Learn more about using components as pages in the Page components section below. You can also register your own custom namespaces—see the Component namespaces documentation.
As your component or project grows, you might find the single-file approach limiting. Livewire offers a multi-file alternative that splits your component into separate files for better organization and IDE support.
To create a multi-file component, pass the --mfc flag:
php artisan make:livewire post.create --mfcThis creates a directory with all related files together:
resources/views/components/post/⚡create/
├── create.php # PHP class
├── create.blade.php # Blade template
├── create.js # JavaScript (optional)
├── create.css # Scoped styles (optional)
├── create.global.css # Global styles (optional)
└── create.test.php # Pest test (optional, with --test flag)The make:livewire command accepts the following options:
| Option | Description |
|---|---|
--sfc | Create a single-file component (default) |
--mfc | Create a multi-file component |
--class | Create a class-based component |
--test | Include a Pest test file |
--js | Include a JavaScript file (multi-file components only) |
--css | Include CSS files (multi-file components only) |
Livewire provides the livewire:convert command to seamlessly convert components between single-file and multi-file formats.
Auto-detect and convert:
php artisan livewire:convert post.create
# Single-file → Multi-file (or vice versa)Explicitly convert to multi-file:
php artisan livewire:convert post.create --mfcThis will parse your single-file component, create a directory structure, split the files, and delete the original.
Explicitly convert to single-file:
php artisan livewire:convert post.create --sfcThis combines all files back into a single file and deletes the directory.
[!warning] Test files are deleted when converting to single-file If your multi-file component has a test file, you'll be prompted to confirm before conversion since test files cannot be preserved in the single-file format.
Single-file components (default):
Multi-file components:
Class-based components:
You can include a Livewire component within any Blade template using the <livewire:component-name /> syntax:
<livewire:component-name />If the component is located in a sub-directory, you can indicate this using the dot (.) character:
resources/views/components/post/⚡create.blade.php
<livewire:post.create />For namespaced components—like pages::—use the namespace prefix:
<livewire:pages::post.create />Regardless of which format you use (single-file, multi-file, or class-based), the component name you use in Blade tags and routes is always the same. The âš¡ emoji prefix and file structure are stripped away automatically:
| Format | File path | Component name |
|---|---|---|
| Single-file | resources/views/components/post/⚡create.blade.php | post.create |
| Multi-file | resources/views/components/post/⚡create/create.php | post.create |
| Class-based | app/Livewire/Post/Create.php | post.create |
| Single-file (namespaced) | resources/views/pages/post/⚡create.blade.php | pages::post.create |
| Multi-file (namespaced) | resources/views/pages/post/⚡create/create.php | pages::post.create |
This means you can switch between formats without changing any of your Blade templates or routes.
To pass data into a Livewire component, you can use prop attributes on the component tag:
<livewire:post.create title="Initial Title" />For dynamic values or variables, prefix the attribute with a colon:
<livewire:post.create :title="$initialTitle" />Data passed into components is received through the mount() method:
<?php
use Livewire\Component;
new class extends Component {
public $title;
public function mount($title = null)
{
$this->title = $title;
}
// ...
};You can think of the mount() method as a class constructor. It runs when the component initializes, but not on subsequent requests within a page's session. You can learn more about mount() and other helpful lifecycle hooks within the lifecycle documentation.
To reduce boilerplate code, you can omit the mount() method and Livewire will automatically set any properties with names matching the passed values:
<?php
use Livewire\Component;
new class extends Component {
public $title; // Automatically set from prop
// ...
};[!warning] These properties are not reactive by default The$titleproperty will not update automatically if the outer:title="$initialValue"changes after the initial page load. This is a common point of confusion when using Livewire, especially for developers who have used JavaScript frameworks like Vue or React and assume these parameters behave like "reactive props" in those frameworks. But, don't worry, Livewire allows you to opt-in to making your props reactive.
When using components as pages, you can pass route parameters directly to your component. The route parameters are automatically passed to the mount() method:
Route::livewire('/posts/{id}', 'pages::post.show');<?php // resources/views/pages/post/⚡show.blade.php
use Livewire\Component;
new class extends Component {
public $postId;
public function mount($id)
{
$this->postId = $id;
}
};Livewire also supports Laravel's route model binding:
Route::livewire('/posts/{post}', 'pages::post.show');<?php // resources/views/pages/post/⚡show.blade.php
use App\Models\Post;
use Livewire\Component;
new class extends Component {
public Post $post; // Automatically bound from route
// No mount() needed - Livewire handles it automatically
};Components can be routed to directly as full pages using Route::livewire(). This is one of Livewire's most powerful features, allowing you to build entire pages without traditional controllers.
Route::livewire('/posts/create', 'pages::post.create');When a user visits /posts/create, Livewire will render the pages::post.create component inside your application's layout file.
Page components work just like regular components, but they're rendered as full pages with access to:
For complete information about page components, including layouts, titles, and advanced routing, see the Pages documentation.
Livewire provides several ways to pass data to your component's Blade view. Each approach has different performance and security characteristics.
The simplest approach is using public properties, which are automatically available in your Blade template:
<?php
use Livewire\Component;
new class extends Component {
public $title = 'My Post';
};<div>
<h1>{{ $title }}</h1>
</div>Protected properties must be accessed with $this->:
public $title = 'My Post'; // Available as {{ $title }}
protected $apiKey = 'secret-key'; // Available as {{ $this->apiKey }}[!info] Protected properties are not sent to the client Unlike public properties, protected properties are never sent to the frontend and cannot be manipulated by users. This makes them safe for sensitive data. However, they are not persisted between requests, which limits their usefulness in most Livewire scenarios. They're best used for static values defined in the property declaration that you don't want exposed client-side.
For complete information about properties, including persistence behavior and advanced features, see the properties documentation.
Computed properties are methods that act like memoized properties. They're perfect for expensive operations like database queries:
use Livewire\Attributes\Computed;
#[Computed]
public function posts()
{
return Post::with('author')->latest()->get();
}<div>
@foreach ($this->posts as $post)
<article wire:key="{{ $post->id }}">{{ $post->title }}</article>
@endforeach
</div>Notice the $this-> prefix - this tells Livewire to call the method and cache the result for the current request only (not between requests). For more details, see the computed properties section in the properties documentation.
Similar to a controller, you can pass data directly to the view using the render() method:
public function render()
{
return $this->view([
'author' => Auth::user(),
'currentTime' => now(),
]);
}Keep in mind that render() runs on every component update, so avoid expensive operations here unless you need fresh data on every update.
While Livewire automatically discovers components in the default resources/views/components/ directory, you can customize where Livewire looks for components and organize them using namespaces.
Component namespaces allow you to organize components into dedicated directories with a clean reference syntax.
By default, Livewire provides two namespaces:
pages:: — Points to resources/views/pages/layouts:: — Points to resources/views/layouts/You can define additional namespaces in your config/livewire.php file:
'component_namespaces' => [
'layouts' => resource_path('views/layouts'),
'pages' => resource_path('views/pages'),
'admin' => resource_path('views/admin'), // Custom namespace
'widgets' => resource_path('views/widgets'), // Another custom namespace
],Then use them when creating, rendering, and routing:
php artisan make:livewire admin::users-table<livewire:admin::users-table />Route::livewire('/admin/users', 'admin::users-table');If you want Livewire to discover components in additional directories beyond the defaults, you can configure them in your config/livewire.php file:
'component_locations' => [
resource_path('views/components'),
resource_path('views/admin/components'),
resource_path('views/widgets'),
],Now Livewire will automatically discover components in all these directories.
For more dynamic scenarios (like package development or runtime configuration), you can register components, locations, and namespaces programmatically in a service provider:
Register an individual component:
use Livewire\Livewire;
// In a service provider's boot() method (e.g., App\Providers\AppServiceProvider)
Livewire::addComponent(
name: 'custom-button',
viewPath: resource_path('views/ui/button.blade.php')
);Register a component directory:
Livewire::addLocation(
viewPath: resource_path('views/admin/components')
);Register a namespace:
Livewire::addNamespace(
namespace: 'ui',
viewPath: resource_path('views/ui')
);This approach is useful when you need to register components conditionally or when building Laravel packages that provide Livewire components.
For class-based components, use the same methods but with the class parameter instead of path:
use Livewire\Livewire;
// In a service provider's boot() method (e.g., App\Providers\AppServiceProvider)
// Register an individual class-based component
Livewire::addComponent(
name: 'todos',
class: \App\Livewire\Todos::class
);
// Register a location for class-based components
Livewire::addLocation(
classNamespace: 'App\\Admin\\Livewire'
);
// Create a namespace for class-based components
Livewire::addNamespace(
namespace: 'admin',
classNamespace: 'App\\Admin\\Livewire',
classPath: app_path('Admin/Livewire'),
classViewPath: resource_path('views/admin/livewire')
);For teams migrating from Livewire v3 or those who prefer a more traditional Laravel structure, Livewire fully supports class-based components. This approach separates the PHP class and Blade view into different files in their conventional locations.
php artisan make:livewire CreatePost --classThis creates two separate files:
app/Livewire/CreatePost.php
<?php
namespace App\Livewire;
use Livewire\Component;
class CreatePost extends Component
{
public function render()
{
return view('livewire.create-post');
}
}resources/views/livewire/create-post.blade.php
<div>
{{-- ... --}}
</div>Use class-based components when:
Use single-file or multi-file components when:
If you want class-based components by default, configure it in config/livewire.php:
'make_command' => [
'type' => 'class',
],You can customize the files (or stubs) Livewire uses to generate new components by running:
php artisan livewire:stubsThis creates stub files in your application that you can modify:
Single-file component stubs:
stubs/livewire-sfc.stub — Single-file componentsMulti-file component stubs:
stubs/livewire-mfc-class.stub — PHP class for multi-file componentsstubs/livewire-mfc-view.stub — Blade view for multi-file componentsstubs/livewire-mfc-js.stub — JavaScript for multi-file componentsstubs/livewire-mfc-test.stub — Pest test for multi-file componentsClass-based component stubs:
stubs/livewire.stub — PHP class for class-based componentsstubs/livewire.view.stub — Blade view for class-based componentsAdditional stubs:
stubs/livewire.attribute.stub — Attribute classesstubs/livewire.form.stub — Form classesOnce published, Livewire will automatically use your custom stubs when generating new components.
Symptom: Error message like "Component [post.create] not found" or "Unable to find component"
Solutions:
config/livewire.php or manually registered in a service providerphp artisan view:clearCommon causes:
Symptom: Errors about duplicate class names when using single-file components
Solution: This can happen if you have multiple single-file components with the same name in different directories. Either: