Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Livewire Toaster Laravel Package

mabdullahsari/livewire-toaster

Livewire Toaster brings toast notifications to your Laravel Livewire apps. Dispatch lightweight, customizable toasts from any component or PHP class, with auto-dismissing messages, multiple variants, and no extra JavaScript wiring required.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin Livewire component that renders a toast stack and listens for a browser event. There is no facade and no service provider API to learn — nearly everything is “dispatch an event, the component shows a toast.”

Install and wire it up once:

composer require mabdullahsari/livewire-toaster

Publish anything it ships (config/views/assets) if the README for your version calls for it:

php artisan vendor:publish --tag=livewire-toaster

Place the component once, in your main app layout, after @livewireScripts (or after @vite if you're on Livewire 3's bundled scripts) and before </body>:

{{-- resources/views/layouts/app.blade.php --}}
    ...
    @livewireScripts
    <livewire:toaster />
</body>
</html>

First use case — the one you'll write within five minutes. In any Livewire component, after a successful save:

public function save(): void
{
    $this->validate();

    $this->post->save();

    $this->dispatch('toast', message: 'Post saved.', type: 'success');
}

Where to look first, in order:

  1. README.md — confirm the exact event name (toast), the payload keys (message, type), and the valid type values for the version you installed. This is the one thing worth verifying rather than assuming; the surface is small but the names matter.
  2. vendor/mabdullahsari/livewire-toaster/resources/views/ — the Blade template tells you exactly which event name and payload it listens for, plus how it styles/types toasts.
  3. vendor/mabdullahsari/livewire-toaster/config/ — duration, position, and any type→class mapping.
  4. src/ — usually a single Livewire component class; skim it once and you know the whole package.

Implementation Patterns

One toaster, many dispatchers

The component is a global sink. Put it in the layout exactly once and dispatch to it from any Livewire component on the page — nested components, child forms, modals, all of them. It is not something you instantiate per-feature.

Centralize the dispatch

Raw $this->dispatch('toast', ...) calls scattered through fifty components get inconsistent fast. Wrap it in a trait so the vocabulary stays fixed and you can swap implementations later:

namespace App\Livewire\Concerns;

trait WithToasts
{
    public function toast(string $message, string $type = 'success'): void
    {
        $this->dispatch('toast', message: $message, type: $type);
    }
}
class EditPost extends Component
{
    use WithToasts;

    public function save(): void
    {
        $this->validate();
        $this->post->save();
        $this->toast('Post saved.');
    }
}

Validation failures as toasts

The default Livewire behaviour surfaces validation errors inline, which is usually what you want. Reach for a toast only when the form is off-screen or the failure is not field-specific:

use Illuminate\Validation\ValidationException;

public function save(): void
{
    try {
        $this->validate();
    } catch (ValidationException $e) {
        $this->toast('Please fix the highlighted fields.', 'error');
        throw $e; // keep inline messages intact
    }

    $this->post->save();
    $this->toast('Post saved.');
}

Re-throwing is the important part — swallowing the exception removes the field-level feedback and leaves users guessing.

Bridging redirects and non-Livewire code

A dispatched browser event dies with the page. If you dispatch and then redirect, the toast is lost. For controller-driven flows — or anything where the response is a redirect — flash to the session and let a persistent listener pick it up:

// Controller
return redirect()->route('posts.index')->with('toast', [
    'message' => 'Post created.',
    'type'    => 'success',
]);

Then in the toaster host (or a tiny always-present Livewire component), listen for the flash on mount and re-dispatch. Do this in one place, or you'll get double toasts on full page loads. If you use wire:navigate, note that the toaster component persists across navigations, so a mount-based flash reader won't re-run — hook into Livewire's navigate event instead.

Job and long-running feedback

Queued jobs can't dispatch to a browser. For “your export is ready,” write a database notification and let a polling/listening component translate it into a toast. Don't try to force the toaster into asynchronous territory.

Testing

Assert on the dispatched event, not on rendered markup — it's stable and fast:

Livewire::test(EditPost::class)
    ->set('title', 'Hello')
    ->call('save')
    ->assertDispatched('toast', message: 'Post saved.', type: 'success');

That's the single highest-value test to write. It catches renamed event names and payload drift when you upgrade the package.

JavaScript side

If you need to toast from Alpine or plain JS, fire the same event name the component listens for on window:

window.dispatchEvent(new CustomEvent('toast', {
    detail: { message: 'Copied to clipboard.', type: 'success' },
}));

Confirm the detail shape against the Blade template — some versions read from event.detail, some from the Livewire dispatch envelope.


Gotchas and Tips

No toaster, no toasts. The single most common “it doesn't work” is a missing <livewire:toaster /> in the layout, or one placed in a layout that a particular page doesn't extend. Check the rendered HTML before debugging anything else.

Don't add it twice. Including the component in both the app layout and a nested layout gives you two listeners and duplicate toasts. One instance, app-wide.

Tailwind purging. If the package's view uses utility classes and you're on a JIT Tailwind build, classes appearing only in vendor/ views get purged. Add the package's view path to your content array, or confirm the package ships precompiled CSS. Symptom: toast appears but is unstyled and vanishes instantly because fixed/z-50/opacity were stripped.

Stacking context and z-index. Toasts inside a modal's stacking context render behind the modal overlay. Since the toaster lives at the layout root this is usually fine — but if you've wrapped your layout in a transform/filter/isolate container, the toaster's z-50 is scoped to that container and can lose to a portal'd modal. Check computed stacking before writing z-index escalation hacks.

Livewire 2 vs 3 event API. On Livewire 2 you may need $this->dispatchBrowserEvent('toast', [...]) and window.addEventListener rather than Livewire.on. Match the calling convention to your Livewire major version, not to a blog post.

Redirect swallows the toast. Covered above, but it's the second most common complaint: dispatch → redirect() → nothing. Always pair redirects with session flash.

Auto-dismiss and accessibility. Long messages disappear before they're read. If the config exposes duration, set it generously for error/info and near-zero (or manual dismiss) for anything a user must act on. Verify the container has aria-live="polite" and role="status"; if it doesn't, that's a legitimate reason to override the published view rather than fork.

Debugging in the browser. Open the console and watch the event fire:

Livewire.on('toast', (payload) => console.log('toast event', payload));

If this logs, the problem is in rendering/positioning/CSS. If it doesn't, the problem is in dispatch (wrong event name, wrong component, wire:ignore swallowing it, or the toaster component not present).

Config caching. After publishing and editing the config, run php artisan config:clear. A cached config from a deploy is a classic “my change did nothing.”

Extension points are limited by design. This is a small package — the realistic customization surface is (a) the published Blade view for markup/styling, (b) the config for duration/position, and (c) your own wrapper trait for the call sites. If you need queueing, grouping, or per-user persistence, you're outside the package's scope and should be looking at a notification system instead.

Pin the version. With a release dated 2026-03-30, verify the illuminate/* and livewire/livewire constraints in its composer.json match your app before upgrading a major Laravel version. A toast package is not worth a dependency conflict.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle