v1 LiVue v1 is here — server-driven reactivity for Laravel using Vue.js Get Started →

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.

app/LiVue/SearchBar.php
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.

app/LiVue/Dashboard.php
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.

app/LiVue/ProductCard.php
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.

app/LiVue/Modal.php
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.

app/LiVue/Cart.php
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:

ModalTest.php (dispatches)
class ModalTest extends Component
{
    public string $message = 'Click to open.';

    public function openModal()
    {
        $this->dispatch(
            'open-modal',
            ['title' => 'From Server!']
        );
    }
}
Modal.php (listens)
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.

JavaScript
// 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.

Blade Template
<!-- 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.

JavaScript
// 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.Echo available globally before LiVue boots

Echo Setup

Initialize Laravel Echo in your application's JavaScript. Make sure it runs before @livueScripts.

resources/js/bootstrap.js
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.

app/LiVue/OrderTracker.php
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.

Public Channel Listener
// 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.

Component Listener
// Syntax: echo-private:channel,EventName
#[On('echo-private:user.123,ProfileUpdated')]
public function handleProfileUpdated($event)
{
    $this->profile = $event['profile'];
}
routes/channels.php
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.

app/LiVue/ChatRoom.php
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.

app/LiVue/OrderDetails.php
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.

app/Events/OrderShipped.php
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.