Events
Component communication through dispatching and listening to events, with support for real-time broadcasting via Laravel Echo.
Dispatching Events
LiVue components can communicate with each other through an event system. From your PHP component, you can dispatch events that other components on the page can listen and react to. There are three dispatch modes, each controlling how the event is delivered.
dispatch() — Broadcast to All
The dispatch() method broadcasts an event to every component on the page that is listening for it. This is the default mode and is useful for global notifications or state synchronization across unrelated components.
namespace App\LiVue;
use LiVue\Component;
class SearchBar extends Component
{
public string $query = '';
public function search()
{
// Broadcast to all listening components
$this->dispatch('search-submitted', ['query' => $this->query]);
}
}
dispatchSelf() — Same Component Only
The dispatchSelf() method delivers the event only to the component instance that emitted it. Other components on the page will not receive it. This is useful for internal state management, such as triggering a refresh after a timer or an internal action.
public function reloadData()
{
// Only this component will receive the event
$this->dispatchSelf('refresh', ['reason' => 'timer']);
}
dispatchTo() — Target a Specific Component
The dispatchTo() method sends the event only to components matching a specific component name. This is ideal for direct, targeted communication — for example, telling a modal component to open, or notifying a cart component that an item was added.
public function addToCart()
{
// Send only to the 'cart' component
$this->dispatchTo('cart', 'item-added', [
'product_id' => $this->productId,
'name' => $this->name,
'price' => $this->price,
]);
}
Tip — Events dispatched from PHP are buffered and included in the AJAX response. The JavaScript runtime then delivers them to the appropriate listeners on the client side. No extra round-trip is needed for the delivery itself.
Listening for Events
To react to dispatched events, your component needs to declare which events it listens for and which methods should handle them. LiVue provides two ways to do this: the #[On] attribute and the $listeners property.
The #[On] Attribute
The recommended approach is to use the #[On] PHP attribute directly on the handler method. This keeps the event name close to the code that handles it. The attribute is repeatable, so a single method can listen to multiple events.
namespace App\LiVue;
use LiVue\Component;
use LiVue\Attributes\On;
class Modal extends Component
{
public bool $show = false;
public string $modalTitle = '';
#[On('open-modal')]
public function open(array $data = [])
{
$this->show = true;
$this->modalTitle = $data['title'] ?? 'Modal';
}
#[On('close-modal')]
public function close()
{
$this->show = false;
$this->modalTitle = '';
}
}
The $listeners Property
Alternatively, you can declare listeners using the $listeners property. This maps event names to method names. Both approaches can be combined; if the same event is defined in both, the #[On] attribute takes precedence.
class Cart extends Component
{
public array $items = [];
protected array $listeners = [
'item-added' => 'addItem',
'item-removed' => 'removeItem',
'cart-cleared' => 'clearAll',
];
public function addItem(array $data = [])
{
$this->items[] = $data;
}
public function removeItem(array $data = [])
{
// Remove item by product_id
}
public function clearAll()
{
$this->items = [];
}
}
Two Components Communicating
Here is a complete example of a page component dispatching an event and a modal component listening for it:
class ModalTest extends Component
{
public string $message = 'Click to open.';
public function openModal()
{
$this->dispatch(
'open-modal',
['title' => 'From Server!']
);
}
}
class Modal extends Component
{
public bool $show = false;
public string $modalTitle = '';
#[On('open-modal')]
public function open(array $data = [])
{
$this->show = true;
$this->modalTitle = $data['title'];
}
}
JavaScript Outside a Template
LiVue does not expose LiVue.on() or LiVue.emit() in the public API. From plain JavaScript, resolve a mounted component and dispatch through its livue helper.
// Resolve a mounted component and use its livue helper
const [cart] = LiVue.getByName('cart');
if (cart) {
cart.livue.dispatch('item-saved', { id: 123 });
cart.livue.dispatchTo('modal', 'open-modal', { title: 'Saved!' });
}
Event Scoping
By default, events dispatched with dispatch() are broadcast to all components on the page that are listening for that event name. While this is convenient, there are situations where you need more precise control over which components receive the event.
Scoping Options from PHP
The three dispatch methods map to three delivery modes:
| Method | Mode | Delivery |
|---|---|---|
| dispatch() | broadcast | All listening components on the page |
| dispatchSelf() | self | Only the component that emitted the event |
| dispatchTo() | to | All components matching the target name |
Client-Side Scoping
You can also dispatch events directly from your Blade templates using the livue object. Client-side dispatches go directly through the JavaScript event bus — no server round-trip is involved.
<!-- Broadcast to all listeners -->
<button @click="livue.dispatch('open-modal', { title: 'Hello' })">
Open (Broadcast)
</button>
<!-- Target a specific component -->
<button @click="livue.dispatchTo('modal', 'open-modal', { title: 'Targeted!' })">
Open (To Modal)
</button>
<!-- Only to this component -->
<button @click="livue.dispatchSelf('refresh')">
Refresh Self
</button>
External JavaScript Dispatch
When you are outside a LiVue template, resolve a component via LiVue.getByName() or LiVue.first(), then call dispatch methods on that component's livue helper.
// Example: dispatch from external JavaScript
const [dashboard] = LiVue.getByName('dashboard');
if (dashboard) {
dashboard.livue.dispatch('notification-received', { message: 'Background sync complete' });
dashboard.livue.dispatchSelf('refresh');
}
Tip — Client-side dispatches (livue.dispatch(), livue.dispatchTo(), livue.dispatchSelf()) and their Blade shortcuts ($dispatch(), $dispatchTo(), $dispatchSelf()) go directly through the JavaScript event bus with no server round-trip. If a listening component has a server-side handler mapped in $listeners or #[On], the bus will trigger an AJAX call to execute that method on the server.
Broadcasting
LiVue integrates with Laravel Echo to enable real-time WebSocket communication. Your components can listen for broadcast events sent via Laravel's broadcasting system, allowing the UI to update instantly when something happens on the server — even if the current user did not trigger the action.
Requirements
Before using broadcasting, ensure you have:
- Laravel Broadcasting configured (Pusher, Ably, Reverb, etc.)
- Laravel Echo installed and configured
-
window.Echoavailable globally before LiVue boots
Echo Setup
Initialize Laravel Echo in your application's JavaScript. Make sure it runs before @livueScripts.
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
forceTLS: true,
});
Listening for Broadcast Events
Use the #[On] attribute with a special prefix to subscribe to Echo channels. The syntax is echo:channel,EventName for public channels.
namespace App\LiVue;
use LiVue\Component;
use LiVue\Attributes\On;
class OrderTracker extends Component
{
public array $updates = [];
#[On('echo:orders,OrderShipped')]
public function handleShipped($event)
{
$this->updates[] = "Order {$event['order_id']} shipped!";
}
}
Tip — When your Laravel event uses broadcastAs() to define a custom event name, prefix it with a dot in the listener: #[On('echo:scores,.score.submitted')].
Channel Types
LiVue supports all three Laravel Echo channel types. The channel type is determined by the prefix in the listener syntax.
Public Channels
Public channels are open to anyone — no authentication required. Use the echo: prefix.
// Syntax: echo:channel,EventName
#[On('echo:orders,OrderCreated')]
public function handleOrderCreated($event)
{
$this->orders[] = $event;
}
Private Channels
Private channels require authentication. Laravel Echo handles authorization automatically through your routes/channels.php file. Use the echo-private: prefix.
// Syntax: echo-private:channel,EventName
#[On('echo-private:user.123,ProfileUpdated')]
public function handleProfileUpdated($event)
{
$this->profile = $event['profile'];
}
Broadcast::channel(
'user.{id}',
function ($user, $id) {
return (int) $user->id === (int) $id;
}
);
Presence Channels
Presence channels extend private channels with awareness of who else is listening. They support special events: here (current users when you join), joining (a user joined), and leaving (a user left). Use the echo-presence: prefix.
class ChatRoom extends Component
{
public array $users = [];
#[On('echo-presence:chat-room,here')]
public function handleUsersHere($users)
{
$this->users = $users;
}
#[On('echo-presence:chat-room,joining')]
public function handleUserJoining($user)
{
$this->users[] = $user;
}
#[On('echo-presence:chat-room,leaving')]
public function handleUserLeaving($user)
{
$this->users = array_filter(
$this->users,
fn($u) => $u['id'] !== $user['id']
);
}
}
Dynamic Channels
When the channel name depends on component state (for example, a specific order ID or room ID), use the getListeners() method instead of static attributes. This lets you interpolate property values into the channel name.
class OrderDetails extends Component
{
public int $orderId;
public function getListeners(): array
{
return [
"echo-private:orders.{$this->orderId},StatusUpdated" => 'handleStatusUpdated',
];
}
public function handleStatusUpdated($event)
{
$this->status = $event['status'];
}
}
Broadcasting Laravel Events
On the server side, create a standard Laravel broadcast event and dispatch it from anywhere in your application. LiVue components that are listening on the corresponding channel will receive the event in real time.
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class OrderShipped implements ShouldBroadcast
{
public function __construct(
public Order $order
) {}
public function broadcastOn(): Channel
{
return new Channel('orders');
}
}
// Dispatch from anywhere
OrderShipped::dispatch($order);
Tip — For Laravel Reverb (first-party WebSocket server), use broadcaster: 'reverb' in your Echo configuration. All channel types and listener syntax work the same regardless of which broadcasting driver you choose.
Lifecycle Events
LiVue also supports Lifecycle Events — a Laravel-based observer pattern that lets you listen to a component's lifecycle from outside (boot, mount, hydrate, method calls, and more). This is separate from component-to-component events documented above.
See the dedicated Lifecycle page for full documentation on lifecycle events, halting, observers, and the #[ObservedBy] attribute.