liberusoftware/notifications-livewire
A Laravel Livewire package from Liberu Software for displaying and managing user notifications. It provides drop-in components for notification lists, unread counts, and mark-as-read actions, making it easy to add a notification UI to your app.
Install the adapter alongside its notification domain package:
composer require liberusoftware/notifications-livewire
Because this is a presentation adapter, expect an underlying domain contract (typically liberusoftware/notifications or Laravel's built-in Notifiable database channel) that produces the notification records this package renders. Install and configure that first — the adapter itself is thin glue.
Where to look first, in order:
config/notifications-livewire.php (after php artisan vendor:publish --tag=notifications-livewire-config) — polling interval, pagination count, view namespace, mark-as-read-on-open behaviour.src/Livewire/ — the actual components. The class names tell you what's exposed for @livewire(...).resources/views/livewire/ — published or vendor views; override these before touching the component classes.First real-world use case: drop a bell into your app layout and let it poll:
{{-- layouts/app.blade.php --}}
@livewire('notifications-bell')
Then fire a notification from anywhere in the app ($user->notify(new InvoicePaid($invoice)) or your domain's equivalent) and confirm it appears. If it does not appear, the problem is almost always the underlying notifier, not this adapter — verify the notifications table row exists before debugging the UI.
Bell + dropdown in the layout. The common pattern is a single polling component in the header, with the list rendered inside it or as a child Livewire component. Keep the heavy query in the child (notifications-list) so the bell can be a lightweight unread-count poller:
@livewire('notifications-bell')
{{-- bell internally renders: --}}
@livewire('notifications-list')
Manual refresh instead of polling. Polling every few seconds is wasteful on busy dashboards. Disable the config interval ('poll' => null or 0 depending on the version) and drive refresh from a domain event:
// In your layout or another Livewire component
protected $listeners = ['echo-private:App.Models.User.'.$this->userId.',NotificationCreated' => '$refresh'];
Wrapping the component with your own policy layer. Because the adapter is presentation-only, authorization usually belongs outside it. A reliable pattern is a parent component that filters the underlying query before rendering:
class MyInbox extends Component
{
public function render()
{
return view('livewire.my-inbox', [
'notifications' => auth()->user()
->notifications()
->where('data->team_id', auth()->user()->current_team_id)
->latest()
->paginate(20),
]);
}
}
Custom notification types. Map notification classes to icons/labels in a small presenter or Blade partial rather than editing vendor views. Publish the views once, then:
@includeFirst([
'notifications.types.'.\Illuminate\Support\Str::kebab(class_basename($notification->type)),
'notifications.types.default',
], ['notification' => $notification])
This keeps type-specific rendering (invoice icon vs. mention icon vs. system alert) out of the adapter entirely.
Toast pattern. If the package exposes a dispatchable, prefer broadcasting a browser event from your notification listener and rendering a toast component in the layout, rather than opening the dropdown programmatically. It is usually less fragile than chaining Livewire events across components.
Mark-as-read flows. The safest pattern is explicit: an "open" click marks one notification read (component action), and a bulk "mark all read" action on the list. Avoid relying on mark-as-read-on-open if you need audit trails — it fires more liberally than you expect (page load, re-render, polling hits).
composer.json and be prepared to read src/ rather than docs. Vendor views published into resources/views/vendor/notifications-livewire/ will silently drift if the package renames a component.composer show liberusoftware/notifications-livewire before building around it; if it fails, fall back to dev-main.$user->notify(...) to work. It renders; it does not send. You still need Laravel's Notifiable trait, php artisan notifications:table migration, and something that creates the notifications (a listener, a queue worker, or Notification::send).->onQueue('notifications') with an afterCommit dispatch or run the worker on the same connection to avoid a "why is the bell empty" support ticket.updating hook as well as render. If unread counts look doubled or read state flickers, check $this->notifications is loaded once in mount() and refreshed via $refresh — not recomputed inline in render() on every poll tick.php artisan config:cache is the usual culprit when polling changes appear to do nothing in production. Also confirm the config tag name actually matched; a failed vendor:publish leaves the package reading the defaults from inside the package, not your local file.composer update will overwrite them.php artisan view:clear, confirm the Livewire assets are included once (not twice) in the layout, check the browser console for the Livewire 404 on livewire/message, and confirm Livewire::test(YourBell::class) works in isolation. If the tinker-level Livewire test passes, the issue is the layout, not the package.How can I help you explore Laravel packages today?