Nitro

Features

Events

Events let components tell each other that something happened. A component dispatches an event, from the browser or from the server, and every component listening with a matching #[On] runs its method.

On this page

Use events for news, not for keeping state. An event might carry a message to show, a list to refresh or a sound to play. A component dispatches an event with $this->dispatch(), or with $dispatch() from its view. Components that listen with #[On] then run their method, with the event's parameters. If several components need to read the same state, use a store instead.

Two ways to say something live, in this page View source ↓
The toaster that listens live, in this page View source ↓

No messages yet.

The first button dispatches notify from its view, in the browser. The second button calls a #[Server] method that dispatches the event on the server. That event arrives with the server's answer and reaches the same listener.

The components

Browser + server
<?php

namespace App\Nitro\Components;

use Nitro\Attributes\Server;
use Nitro\Component;

class Notifier extends Component
{
    #[Server]
    public function save(): void
    {
        // A demo: nothing is saved. A real method would write to the database first.
        $this->dispatch('notify', 'Saved on the server at '.now()->format('H:i:s'), 'success');
    }
}
Browser + server
<?php

namespace App\Nitro\Components;

use Nitro\Attributes\On;
use Nitro\Component;

class Toaster extends Component
{
    public array $toasts = [];

    public int $next = 1;

    /** Runs when any component dispatches notify, for example with $this->dispatch('notify', 'Saved'). */
    #[On('notify')]
    public function notify(string $message, string $tone = 'info'): void
    {
        $this->toasts[] = ['id' => $this->next++, 'message' => $message, 'tone' => $tone];
        $this->toasts = array_slice($this->toasts, -3);
    }

    public function dismiss(int $id): void
    {
        $this->toasts = array_values(array_filter($this->toasts, fn ($toast) => $toast['id'] !== $id));
    }
}

Dispatching and listening for events

PHP
$this->dispatch('notify', 'Saved');                        // Every listener.
$this->dispatch('notify', 'Saved')->to(Toaster::class);    // Only Toaster components.
$this->dispatch('refresh')->self();                        // Only this component.

#[On('notify')]
public function notify(string $message, string $tone = 'info'): void { ... }
  • Every listener on the page hears an event by default. Use ->to(Toaster::class) to reach only the components of that class, or ->self() to reach only the component that dispatches it.
  • Parameters are passed to the listener in order, as arguments. You can name them for readability, dispatch('post-saved', id: $post->id), but the names don't match them to the listener's parameters: the order does.
  • A listener runs in the browser, or on the server if it is a #[Server] method.
  • Events dispatched on the server by a #[Server] method arrive with its answer, and are dispatched in the browser at that point.

Dispatching from a view

Blade
<button nitro:click="$dispatch('notify', 'Copied')">Copy</button>
<button nitro:click="$dispatchTo('toaster', 'notify', 'Copied')">Copy</button>
<button nitro:click="$dispatchSelf('refresh')">Refresh</button>
<button nitro:click="$parent->save()">Save the form around it</button>

$parent->save() calls a method of the component whose view placed this one. This lets a child ask its parent to act, without an event.

Listening on the window

An event that you don't narrow with ->to() or ->self() is also a DOM event on the window, so your own scripts can listen for it:

JavaScript
window.addEventListener('notify', (e) => console.log(e.detail.params));   // ['Saved', 'success']

Listening to broadcasts

#[On('echo:...')] listens to Laravel broadcasting through your application's Laravel Echo (window.Echo, with Reverb or Pusher). The component subscribes when it appears, and it stops listening when it leaves the page.

PHP
#[On('echo:orders,OrderPlaced')]                         // A public channel.
public function orderPlaced(array $event): void { $this->orders[] = $event['order']; }

#[On('echo-private:orders.{order.id},OrderShipped')]     // A private channel. {order.id} reads the state.
#[Server]
public function orderShipped(array $event): void { $this->order = Order::find($this->order['id'])->toArray(); }

#[On('echo-presence:chat,here')]                          // A presence channel: here, joining, leaving.
public function here(array $users): void { $this->online = $users; }

#[On('echo-notification:App.Models.User.{userId}')]       // Notifications.
public function notified(array $notification): void { $this->unread++; }
  • A {property} in a channel name reads the component's state. It must name a public property, and the build tells you if it doesn't.
  • For an event with a custom name (set with broadcastAs()), write the name with a leading dot, as in echo:orders,.order.placed.
  • Laravel authorizes private and presence channels, just as it does for any Echo listener.

Next steps