Notifications
The notifications bell is an opt-in module: a fluent Notification builder that sends a
self-describing payload through Laravel’s native notification channels, and a Notifications bell
component that lists, reads, and dismisses them. Nothing is enabled until you publish the migration
and mark your notifiable model.
Prerequisite
Section titled “Prerequisite”The bell
Section titled “The bell”Notifications::make();- channel:""
- endpoint:"/lattice/notifications"
- pollingInterval:null
- slideOut:false
The live preview above can’t reach a real endpoint from a static docs page, so it renders empty — in your app it hydrates from the config-driven endpoint on mount.
Sending a notification
Section titled “Sending a notification”Notification::make() builds the payload fluently, then ->send() or ->sendToDatabase() dispatches
it to any notifiable:
use Lattice\Lattice\Core\Enums\Variant;use Lattice\Lattice\Notifications\Notification;
Notification::make() ->title('Order #1234 shipped') ->body('Tracking is now available.') ->icon('truck') ->variant(Variant::Success) ->href('/orders/1234') ->action(MarkOrderSeenAction::class, ['order_id' => 1234]) ->link('Track shipment', '/orders/1234/track') ->send($order->user);->title()/->body()— the headline and supporting text.->icon($name)— a sprite icon name or a backed enum case.->variant(Variant::…)— the sameVariantenum toasts and callouts use; drives the bell item’s accent color.->href($url)— makes the whole row a link: clicking the title/body navigates to$url(an internal app route, followed as an Inertia visit) and marks the notification read.->action($actionClass, $arguments = [], $label = null)— attaches a real Lattice action button, referenced by class name.->link($label, $url)— attaches a plain link button (an internal app route) instead of (or alongside) an action.->send($notifiable)— delivers overdatabaseandbroadcast.->sendToDatabase($notifiable)— persists only, without a broadcast event.
Reusable notification classes
Section titled “Reusable notification classes”For a notification that also needs other channels — mail, Slack, SMS — don’t reach for a Lattice
base class. Write a plain Laravel notification and return the Notification builder’s payload from
toArray(), the same shape ->send() produces:
use Illuminate\Notifications\Messages\MailMessage;use Illuminate\Notifications\Notification as LaravelNotification;use Lattice\Lattice\Core\Enums\Variant;use Lattice\Lattice\Notifications\Notification;
class OrderShipped extends LaravelNotification{ public function __construct(private readonly Order $order) {}
public function via(object $notifiable): array { return ['mail', 'database', 'broadcast']; }
public function toArray(object $notifiable): array { return Notification::make() ->title("Order #{$this->order->number} shipped") ->body('Tracking is now available.') ->variant(Variant::Success) ->href("/orders/{$this->order->id}") ->toArray(); }
public function toMail(object $notifiable): MailMessage { return (new MailMessage)->line("Order #{$this->order->number} has shipped."); }}$order->user->notify(new OrderShipped($order));Laravel uses the array returned by toArray() for both the database and broadcast channels, so
the bell renders it and pushes it live exactly like ->send() does — no Lattice base class involved,
just the builder’s own toArray() as the reusable payload getter.
Placing the bell
Section titled “Placing the bell”Drop Notifications::make() into a Topbar like any other
component:
use Lattice\Lattice\Core\Components\Stack;use Lattice\Lattice\Core\Enums\Side;use Lattice\Lattice\Layouts\Components\Topbar;use Lattice\Lattice\Notifications\Components\Notifications;
Topbar::make('app-topbar')->sticky()->items([ Stack::make()->direction('row')->float(Side::End)->schema([ Notifications::make(), ]),]);It defaults to a popover anchored under the bell. Call ->slideOut() for a full-height panel that
slides in from the trailing edge instead — a better fit for a dense topbar or a mobile layout:
Notifications::make()->slideOut();Configuration
Section titled “Configuration”'notifications' => [ 'endpoint' => 'lattice/notifications', 'middleware' => ['web', 'auth'], 'per_page' => 15, 'polling_interval' => null, 'prune_after_days' => 30,],endpoint/middleware— where the list and mutation routes are served, same convention as every other Lattice endpoint.per_page— page size for the list and its “load more” pagination.polling_interval— seconds between polling refetches;nulldisables polling (the default — rely on realtime, or set an explicit interval as a fallback). Override per bell with->pollingInterval($seconds).prune_after_days— how long a read notification is kept before pruning deletes it.
Realtime and polling
Section titled “Realtime and polling”Each notifiable gets a private channel — NotificationChannel::for($notifiable), the same channel
Laravel’s broadcast notifications use (or receivesBroadcastNotificationsOn() if the model defines
it). The bell subscribes to it with useEchoNotification from @laravel/echo-react and prepends
whatever arrives, no page reload needed.
See Realtime for the broadcasting setup (Echo, Reverb) this depends on — this is a
different mechanism from a page’s declarative Listen listeners, purpose-built for one notifiable’s
private notification stream.
Retention
Section titled “Retention”Read notifications older than prune_after_days are deleted by an Artisan command, not
automatically:
php artisan lattice:notifications:pruneSchedule it in your application:
use Illuminate\Support\Facades\Schedule;
Schedule::command('lattice:notifications:prune')->daily();Unread notifications are never pruned, regardless of age.