rohitshakya/laravel-beacon
| Install | |
|---|---|
composer require rohitshakya/laravel-beacon |
|
| Latest Version: | 2.0.3 |
| PHP: | ^8.2 |
| License: | MIT |
| Last Updated: | Apr 27, 2026 |
| Links: | GitHub · Packagist |
🔔 Beacon
Realtime Notification UI for Laravel
Like a lighthouse in the dark, Beacon signals new activity to your users.
Beacon is a drop-in notification UI for Laravel that provides a topbar dropdown, inbox page, and realtime updates using Livewire and broadcasting.
It is designed to be elegant, customizable, and easy to integrate into any Laravel app — and it works for any notifiable model, not just App\Models\User.
Why "Beacon"?
A beacon is a guiding signal — a lighthouse that alerts ships of activity and direction.
This package acts the same way:
- Signals new notifications
- Guides users to important updates
- Works in realtime
- Always visible from the topbar
Instead of silently storing notifications in the database, Beacon announces them to users through UI, events, and realtime broadcasting.
Features
- Topbar notification dropdown
- Full inbox page
- Realtime updates (Echo / Reverb / Pusher)
- Livewire powered UI
- Multi-notifiable — works with
User,Reseller,Employee, or any model that uses Laravel'sNotifiabletrait - Multiple topbars on the same page (each bound to its own private channel)
- Fully customizable Blade views
- Browser events for JS integrations
- Plug-and-play config
📦 Installation
composer require rohitshakya/laravel-beacon
Publish config:
php artisan vendor:publish --tag=beacon-config
Publish views (optional):
php artisan vendor:publish --tag=beacon-views
Quick Usage
1. Add the topbar
The simplest case — render for the currently authenticated user:
<x-beacon::topbar />
Or mount the Livewire component directly:
<livewire:beacon.topbar />
Both fall back to auth()->user() when no notifiable is passed.
Render for any notifiable
Pass any model that uses the Notifiable trait:
{{-- For a Reseller --}}
<x-beacon::topbar :notifiable="$reseller" />
{{-- For an Employee --}}
<x-beacon::topbar :notifiable="$employee" />
Or via the Livewire tag with explicit class + id:
<livewire:beacon.topbar
:notifiable-class="App\Models\Reseller::class"
:notifiable-id="$reseller->id" />
The same applies to the inbox:
<x-beacon::inbox :notifiable="$reseller" />
{{-- or --}}
<livewire:beacon.inbox
:notifiable-class="App\Models\Reseller::class"
:notifiable-id="$reseller->id" />
Security note: the
notifiableClassandnotifiableIdprops on the Livewire components are marked#[Locked], so the client cannot mutate them after mount. The backend must decide which notifiable a given page may view.
Multiple topbars on one page
You can render multiple topbars side by side — for example, an admin dashboard showing a personal bell and a reseller-impersonation bell. Each one binds its own private Echo channel, so they update independently:
<x-beacon::topbar /> {{-- current user --}}
<x-beacon::topbar :notifiable="$reseller" /> {{-- reseller, separate channel --}}
2. Send a notification
$user->notify(new SomeNotification());
$reseller->notify(new SomeNotification());
$employee->notify(new SomeNotification());
Beacon will automatically appear in UI for whoever the topbar is mounted for.
3. Listen in JS (optional)
window.addEventListener('beacon:notification', (e) => {
console.log('New notification', e.detail);
});
Realtime Setup
Beacon supports:
- Laravel Reverb
- Pusher
- Soketi
- Ably
- Any Echo driver
Make sure Echo is running. You do not need to call Echo.private(...)
yourself — the topbar view binds the resolved channel for you.
The channel name is derived from the notifiable's class FQCN by default:
| Notifiable | Channel |
|---|---|
App\Models\User with id 1 |
App.Models.User.1 |
App\Models\Reseller with id 5 |
App.Models.Reseller.5 |
App\Models\Employee with id 9 |
App.Models.Employee.9 |
This matches Laravel's built-in Notifiable::receivesBroadcastNotificationsOn()
convention, so no custom routing is needed on the broadcaster.
Configuration
config/beacon.php
return [
'views' => [
'inbox' => 'beacon::inbox.default',
'item' => 'beacon::item.default',
],
'topbar' => [
'limit' => 8,
],
'realtime' => [
'enabled' => true,
'resolver' => \RohitShakya\Beacon\Support\DefaultChannelResolver::class,
'channel_pattern' => '{class}.{id}',
'channels' => [
// \App\Models\User::class => 'App.Models.User.{id}',
],
'browser_event' => 'beacon:notification',
],
'notifications' => [
// \App\Notifications\InvoicePaid::class => [...],
],
];
Config Options Explained
Views
Override the inbox and per-item Blade templates.
'views' => [
'inbox' => 'beacon::inbox.default',
'item' => 'beacon::item.default',
],
The topbar view is the Livewire view (beacon::livewire.topbar) — publish it
with php artisan vendor:publish --tag=beacon-views and edit
resources/views/vendor/beacon/livewire/topbar.blade.php if you want to
customize it.
Topbar
'topbar' => [
'limit' => 8,
],
| Option | Description |
|---|---|
| limit | notifications shown in dropdown |
Realtime
'realtime' => [
'enabled' => true,
'resolver' => \RohitShakya\Beacon\Support\DefaultChannelResolver::class,
'channel_pattern' => '{class}.{id}',
'channels' => [
// \App\Models\User::class => 'App.Models.User.{id}',
],
'browser_event' => 'beacon:notification',
],
| Option | Description |
|---|---|
| enabled | Enable Echo listening |
| resolver | FQCN that resolves the broadcast channel for a given notifiable (see Custom Channel Resolver) |
| channel_pattern | Default pattern used by DefaultChannelResolver. {class} is replaced with the FQCN (\\ → .); {id} with the key |
| channels | Per-class overrides keyed by FQCN. Wins over channel_pattern when the notifiable matches |
| browser_event | Event fired in the browser |
Per-class override example
'realtime' => [
'channels' => [
\App\Models\Reseller::class => 'tenants.{id}.reseller',
\App\Models\Employee::class => 'org.employee.{id}',
],
],
Custom Channel Resolver
Beacon resolves the broadcast channel server-side for the notifiable that the topbar/inbox is rendered for, then ships the channel name to the frontend through the Livewire props. The browser never has to figure out the channel name — and you can derive the channel from anything you have access to in PHP (tenant, organization, custom user key, etc.).
1. Implement the contract
namespace App\Beacon;
use RohitShakya\Beacon\Support\Contracts\ChannelResolver;
class TenantChannelResolver implements ChannelResolver
{
public function resolve($notifiable = null): ?string
{
$notifiable = $notifiable ?: auth()->user();
if (! $notifiable) {
return null;
}
// Whatever runtime logic you need — DB lookup, tenant scope, etc.
return sprintf(
'tenants.%s.%s.%s',
tenant()->id,
str_replace('\\', '.', $notifiable::class),
$notifiable->getKey(),
);
}
}
Return null when there is no notifiable; the frontend will skip Echo binding
cleanly.
2. Point the config at it
// config/beacon.php
'realtime' => [
'enabled' => true,
'resolver' => \App\Beacon\TenantChannelResolver::class,
// channel_pattern / channels are ignored — your resolver controls the name
],
The resolver is a string FQCN, so php artisan config:cache continues to work.
3. That's it
The package's topbar view receives the resolved channel as a Livewire prop and
passes it to window.beaconTopbarBind(channel, eventName) automatically. You do
not need to call beaconTopbarBind from your own app.js.
Customizing UI
Publish views:
php artisan vendor:publish --tag=beacon-views
Then edit:
resources/views/vendor/beacon/
You can redesign everything.
Browser Events
Beacon dispatches:
beacon:notification
Example:
window.addEventListener('beacon:notification', e => {
toast(e.detail.title)
})
When multiple topbars are mounted (different notifiables), each one binds its
own private channel and fires the same event — e.detail carries the
notification payload as it arrived from Echo.
Testing Notifications
$user->notify(new TestNotification());
$reseller->notify(new TestNotification());
Open two tabs → watch realtime.
Use Cases
- SaaS dashboards (per-user bell)
- Admin panels (impersonate / view another notifiable's bell)
- HR systems (employee notifications)
- CRM (account manager + contact notifications)
- ISP / reseller panels (reseller-scoped bells)
- Any Laravel app needing notifications
Contributing
PRs welcome.
git clone
composer install
npm install
License
MIT
Author
Built with ❤️ for Laravel ecosystem.