Overview
Lyger Livewire provides a server-side reactive component system that allows you to build dynamic interfaces without writing JavaScript. Components automatically handle updates, events, and state management.
Lyger Livewire is inspired by Laravel Livewire but built specifically for the Lyger framework with full integration support.
Creating Components
Create Component Class
Extend the Lyger\Livewire\Component base class and implement the render() method:<?php
namespace App\Livewire;
use Lyger\Livewire\Component;
class Counter extends Component
{
public int $count = 0;
public function increment()
{
$this->count++;
}
public function decrement()
{
$this->count--;
}
public function render(): string
{
return <<<HTML
<div>
<h2>Counter: {$this->count}</h2>
<button wire:click="increment">+</button>
<button wire:click="decrement">-</button>
</div>
HTML;
}
}
Register Component
Register your component with the Livewire manager:use Lyger\Livewire\Manager;
use App\Livewire\Counter;
Manager::register('counter', Counter::class);
Use in Views
Include the component in your views using the component name:<div id="app">
@livewire('counter')
</div>
Component Lifecycle
Mount Method
The mount() method is called when a component is first created:
class UserProfile extends Component
{
public string $name = '';
public string $email = '';
public function mount(int $userId): void
{
$user = User::find($userId);
$this->name = $user->name;
$this->email = $user->email;
}
public function render(): string
{
return Blade::render('profile.user', [
'name' => $this->name,
'email' => $this->email,
]);
}
}
Public Properties
All public properties are automatically tracked and synced with the frontend:
class SearchForm extends Component
{
public string $query = '';
public array $results = [];
public bool $loading = false;
public function search()
{
$this->loading = true;
$this->results = $this->performSearch($this->query);
$this->loading = false;
}
// Properties are automatically available in the view
public function render(): string
{
return Blade::render('search.form', $this->getPublicProperties());
}
}
Data Binding
Properties are automatically synchronized between the server and client:
class ContactForm extends Component
{
public string $name = '';
public string $email = '';
public string $message = '';
public function submit()
{
// Validate and process form
$this->validate([
'name' => ['required', 'min:3'],
'email' => ['required', 'email'],
'message' => ['required', 'min:10'],
]);
// Send email or save to database
$this->reset('name', 'email', 'message');
}
public function render(): string
{
return <<<HTML
<form wire:submit="submit">
<input type="text" wire:model="name" placeholder="Name">
<input type="email" wire:model="email" placeholder="Email">
<textarea wire:model="message" placeholder="Message"></textarea>
<button type="submit">Send</button>
</form>
HTML;
}
}
Validation
Components include built-in validation support:
class RegistrationForm extends Component
{
public string $username = '';
public string $password = '';
public array $errors = [];
public function register()
{
try {
$validated = $this->validate([
'username' => ['required', 'min:3', 'max:20'],
'password' => ['required', 'min:8'],
], [
'username.required' => 'Username is required',
'password.min' => 'Password must be at least 8 characters',
]);
// Create user account
User::create($validated);
return $this->redirect('/dashboard');
} catch (ValidationException $e) {
$this->errors = $e->getErrors();
}
}
public function render(): string
{
return Blade::render('auth.register', [
'username' => $this->username,
'password' => $this->password,
'errors' => $this->errors,
]);
}
}
Error Handling
protected function addError(string $field, string $message): void
{
$this->errors[$field] = $message;
}
Events
Emit Events
Emit to Parent
Browser Events
Emit events to communicate between components:class PostCreator extends Component
{
public string $title = '';
public string $content = '';
public function createPost()
{
$post = Post::create([
'title' => $this->title,
'content' => $this->content,
]);
// Emit event to notify other components
return $this->emit('postCreated', $post->id);
}
public function render(): string
{
return Blade::render('posts.create');
}
}
Use emitUp() to send events to parent components:class ChildComponent extends Component
{
public function notifyParent()
{
return $this->emitUp('childUpdated', [
'timestamp' => time(),
]);
}
}
Dispatch browser-level events:class Notification extends Component
{
public function showAlert()
{
return $this->dispatchBrowserEvent('alert', [
'message' => 'Operation completed!',
'type' => 'success',
]);
}
}
Component Traits
Lyger Livewire includes reusable traits for common functionality:
WithEvents
use Lyger\Livewire\Component;
use Lyger\Livewire\WithEvents;
class EventDrivenComponent extends Component
{
use WithEvents;
protected function mount(): void
{
$this->listen('userUpdated', function($userId) {
$this->refreshUserData($userId);
});
}
}
WithFileUploads
use Lyger\Livewire\WithFileUploads;
class FileUploader extends Component
{
use WithFileUploads;
public function handleUpload()
{
$this->validateFile('document', ['required', 'max:2048']);
$file = $this->request->file('document');
$path = $this->upload('document', $file);
return $this->redirect("/files?uploaded={$path}");
}
}
use Lyger\Livewire\WithPagination;
class UserList extends Component
{
use WithPagination;
protected int $perPage = 10;
public function render(): string
{
$users = User::paginate($this->perPage, $this->page);
return Blade::render('users.list', [
'users' => $users,
'pagination' => $this->pagination(),
]);
}
}
WithSearch
use Lyger\Livewire\WithSearch;
class SearchableTable extends Component
{
use WithSearch;
protected array $searchable = ['name', 'email', 'description'];
public function render(): string
{
$query = User::query();
$results = $this->applySearch($query)->get();
return Blade::render('users.searchable', [
'results' => $results,
'search' => $this->search,
]);
}
}
Actions and Methods
Calling Methods
Component methods can be called from the frontend:
class TodoList extends Component
{
public array $todos = [];
public function addTodo(string $title)
{
$this->todos[] = [
'id' => uniqid(),
'title' => $title,
'completed' => false,
];
}
public function toggleTodo(string $id)
{
foreach ($this->todos as &$todo) {
if ($todo['id'] === $id) {
$todo['completed'] = !$todo['completed'];
}
}
}
public function deleteTodo(string $id)
{
$this->todos = array_filter($this->todos, fn($t) => $t['id'] !== $id);
}
}
Redirects
protected function redirect(string $url): array
{
return ['redirect' => $url];
}
protected function redirectToRoute(string $route, array $params = []): array
{
$url = $route;
foreach ($params as $key => $value) {
$url = str_replace("{{$key}}", $value, $url);
}
return $this->redirect($url);
}
Example usage:
public function saveAndRedirect()
{
$this->save();
return $this->redirect('/dashboard');
}
public function viewUser(int $userId)
{
return $this->redirectToRoute('/users/{id}', ['id' => $userId]);
}
Authentication
Components have built-in authentication helpers:
class ProtectedComponent extends Component
{
public function mount(): void
{
if (!$this->isAuthenticated()) {
return $this->redirect('/login');
}
}
public function performAction()
{
$user = $this->user();
if (!$user) {
$this->addError('auth', 'You must be logged in');
return;
}
// User data available in $user array
$userId = $user['id'];
$userName = $user['name'];
}
}
Request Handling
The Livewire Manager handles incoming AJAX requests:
use Lyger\Http\Request;
use Lyger\Livewire\Manager;
// In your routes or middleware
$request = Request::capture();
if ($request->isLivewire()) {
return Manager::handle($request);
}
The Manager automatically handles component instantiation, property updates, and method execution based on the request payload.
Best Practices
Keep Components Focused
Each component should have a single responsibility. Break complex UIs into smaller, reusable components.
Use Public Properties Wisely
Only make properties public if they need to be tracked and synced. Use protected/private for internal state.
Validate User Input
Always validate data before processing, especially for security-sensitive operations.
Handle Errors Gracefully
Use try-catch blocks and provide meaningful error messages to users.
Optimize Rendering
Cache expensive computations and avoid unnecessary database queries in the render method.
API Reference
Component Methods
| Method | Description |
|---|
mount(...$params) | Called when component is first created |
render() | Returns the component HTML (required) |
getPublicProperties() | Gets all public properties as array |
callMethod($method, $params) | Executes a component method |
validate($rules, $messages) | Validates component data |
addError($field, $message) | Adds validation error |
reset(...$properties) | Resets properties to default |
emit($event, ...$params) | Emits component event |
emitUp($event, ...$params) | Emits event to parent |
dispatchBrowserEvent($event, $data) | Dispatches browser event |
redirect($url) | Redirects to URL |
user() | Gets current authenticated user |
isAuthenticated() | Checks if user is authenticated |
Manager Methods
| Method | Description |
|---|
Manager::register($name, $class) | Registers a component |
Manager::get($name) | Gets component instance |
Manager::handle($request) | Handles Livewire request |