livewire/volt
Volt is a functional API for Laravel Livewire that enables single-file components, keeping PHP component logic and Blade templates together in one file for a clean, streamlined developer experience.
Installation:
composer require livewire/volt
Volt integrates seamlessly with Livewire, so ensure Livewire is installed (livewire/livewire).
Generate a Volt Component:
php artisan make:volt Counter
This creates a single-file component (SFC) at resources/views/components/counter.volt.php with both PHP logic and Blade template in one file.
First Use Case: Use Volt to render a simple counter component:
// resources/views/components/counter.volt.php
<div>
<button wire:click="increment">Count: <?php echo $count; ?></button>
</div>
<?php
class Counter extends Livewire\Component {
public int $count = 0;
public function increment() {
$this->count++;
}
}
Render it in a Blade view:
@volt('Counter')
Structure: Volt components combine PHP logic and Blade templates in one file (.volt.php). Example:
<!-- resources/views/components/user-profile.volt.php -->
<div>
<h1><?php echo $name; ?></h1>
<p>Email: <?php echo $email; ?></p>
</div>
<?php
class UserProfile extends Livewire\Component {
public string $name;
public string $email;
public function mount(string $name, string $email) {
$this->name = $name;
$this->email = $email;
}
}
Rendering:
Use the @volt directive in Blade views:
@volt('UserProfile', ['name' => 'John', 'email' => '[email protected]'])
Or use the functional API:
Volt::component('UserProfile', ['name' => 'John', 'email' => '[email protected]']);
Dynamic Components:
// Dynamically render components based on conditions
$component = $user->isAdmin() ? 'AdminDashboard' : 'UserDashboard';
Volt::component($component);
State Management:
Use with() to pass data or state:
Volt::component('OrderSummary')
->with('order', $order)
->with('user', $user);
Query Parameters: Pass query parameters directly:
Volt::component('SearchResults')->withQueryParams(request()->query());
Fragments:
Render partials with fragment():
Volt::fragment('notifications', function () {
return '<div>Notifications</div>';
});
Validation: Define rules in the component class:
use Illuminate\Validation\Rules;
public function rules() {
return [
'email' => ['required', 'email'],
'password' => ['required', Rules::password],
];
}
Listeners:
Use wire:model and wire:click in Blade:
<input wire:model="email" type="email">
<button wire:click="submit">Submit</button>
Testing: Use Volt-specific testing helpers:
$this->assertSeeVolt('Count: 1');
$this->assertDontSeeVolt('Error');
View Path Configuration:
Ensure livewire.view_path is set in config/livewire.php to point to your Volt components directory (e.g., resources/views/components).
Class vs. Functional API:
--class flag with make:volt, ensure the component extends Livewire\Component.State Property Serialization:
Avoid serializing complex objects in state properties. Use protected $skipRule = true; for non-serializable properties.
Blade vs. PHP in Volt:
<?php ... ?> for PHP logic and @ directives for Blade syntax. Mixing them incorrectly can cause parsing errors.<div>
<?php if ($show): ?>
<p>Visible content</p>
<?php endif; ?>
</div>
Caching Issues: Clear view cache if components aren’t updating:
php artisan view:clear
php artisan cache:clear
Check for Typos: Volt is strict about component names and paths. Verify the component file exists and the name matches exactly.
Use dd() for State:
Debug component state by dumping properties:
public function mount() {
dd($this->state);
}
Log Errors:
Enable Livewire logging in config/livewire.php:
'log' => env('LIVEWIRE_LOG', true),
Custom Directives: Extend Volt by creating custom Blade directives in a service provider:
Blade::directive('voltIf', function ($expression) {
return "<?php if ({$expression}): ?>";
});
Precompiler Hooks: Override Volt’s precompiler behavior by publishing and modifying the precompiler:
php artisan vendor:publish --tag=volt.precompiler
Testing Helpers:
Extend Volt’s testing capabilities by adding custom assertions to VoltTestCase:
public function assertVoltHasClass($component, $class) {
$this->assertStringContainsString($class, $this->getVoltHtml($component));
}
Lazy Loading:
Use wire:ignore for non-reactive elements to reduce Livewire’s workload:
<div wire:ignore>
<!-- Non-reactive content -->
</div>
Memoization: Cache expensive computations in properties:
public function getExpensiveDataProperty() {
return $this->cacheMemoize('expensiveData', function () {
return ExpensiveModel::query()->get();
});
}
Avoid Heavy Logic in Render: Move complex logic to methods and call them in the template:
<div>
<?php echo $this->generateReport(); ?>
</div>
View Path Overrides:
Override the default view path in config/livewire.php:
'view_path' => resource_path('views/custom-components'),
Component Aliases:
Define aliases in config/livewire.php for cleaner component names:
'component_aliases' => [
'UserProfile' => 'user-profile',
],
Class Components:
Ensure the component class is at the bottom of the .volt.php file to avoid parsing issues.
From Traditional Livewire:
Convert existing Livewire components to Volt by moving the class definition into the .volt.php file and updating the view path.
From Blade:
Replace @component('name') with @volt('name') and move logic into the component class.
Dynamic Imports: Use Volt with dynamic imports for code splitting:
Volt::component('LazyComponent')->lazy();
Slot Content: Support slots in Volt components:
<div>
{{ $slot }}
</div>
<?php
class ParentComponent extends Livewire\Component {
public function render() {
return view('components.parent')->slot('Child content');
}
}
Render with:
@volt('ParentComponent') @slot @endvolt
Model Binding: Bind route models directly to component properties:
public function mount(User $user) {
$this->user = $user;
}
Access via:
@volt('UserProfile', ['user' => $user])
How can I help you explore Laravel packages today?