The Problem With Session Flash Messages

Flash messages are a Laravel convention most developers accept without questioning. You call session()->flash('success', 'Project saved.') in a controller, check session('success') in the Blade layout, and render a <div> with appropriate styling. It works. It is even testable. But it produces UX that no user would describe as delightful.

The problems with the standard flash message approach are well-known to anyone who has polished a Laravel application:

The alert blocks content. A flash message rendered in a fixed position in the layout pushes content down or overlaps it. The user has to read it and dismiss it before continuing.

There is no animation. Content appears and disappears without visual feedback, making it easy to miss notifications that appear during a page transition.

Styling is manual. Every project has its own @if (session('success')) conditional, its own colour scheme, and its own dismiss button implementation — all of which get built and rebuilt from scratch.

Livewire complicates it further. Flash messages are set in PHP but consumed in the next page render. For Livewire component actions that do not cause a full page reload, flash messages do not work at all without a custom event system.

Sonner solves all of this with a JavaScript toast notification system that is small (8KB gzipped), beautifully animated, accessible, and highly configurable. Laravel Sooner integrates Sonner into the Laravel PHP ecosystem so you can dispatch toasts from a controller, an action class, a queued job, or a Livewire component without writing JavaScript.

Basic Usage

After installation, dispatching a toast from a controller is a single static call:

use AmjadIqbal\LaravelSooner\Facades\Sooner;

class ProjectController extends Controller
{
    public function store(StoreProjectRequest $request)
    {
        $project = Project::create($request->validated());

        Sooner::success("Project \"{$project->title}\" created successfully!");

        return redirect()->route('projects.index');
    }

    public function destroy(Project $project)
    {
        $project->delete();

        Sooner::warning('Project deleted. This action cannot be undone.');

        return redirect()->route('projects.index');
    }
}

In your layout, add the single directive:

@soonerToasts

That is the entire integration for a standard Blade application. No Alpine.js required, no JavaScript configuration.

How It Works Internally

The Sooner facade writes toast definitions to the Laravel session in the same request that dispatches them. The @soonerToasts directive reads the session on the next page render and outputs the Sonner initialisation JavaScript:

<script>
document.addEventListener('DOMContentLoaded', function() {
    Toaster.init({ position: 'bottom-right', richColors: true });
    toast.success('Project "My App" created successfully!');
});
</script>

The toast definitions are serialised with type, message, title, and options, then decoded and rendered by the directive. The session key is cleared after rendering to prevent toasts from reappearing on subsequent page loads — matching the standard flash message lifecycle.

Livewire Integration

For Livewire component actions that do not trigger a full page reload, the package provides a Livewire event API:

class ProjectForm extends Component
{
    public function save()
    {
        $this->validate();

        $project = Project::create($this->all());

        // Dispatch via Livewire event — works without page reload
        $this->dispatch('sooner.success', "Project \"{$project->title}\" saved!");
    }
}

The @soonerToasts directive registers an Alpine.js event listener for sooner.* events and passes them to Sonner, so toasts dispatched from Livewire components appear immediately without a page transition.

Configuration Options

The package is configurable via config/sooner.php:

return [
    'position' => 'bottom-right',     // top-left, top-center, top-right, etc.
    'duration' => 4000,               // milliseconds before auto-dismiss
    'rich_colors' => true,            // semantic colours per toast type
    'close_button' => false,          // show manual dismiss button
    'expand' => false,                // expand all toasts simultaneously
    'max_visible' => 3,               // maximum simultaneously visible toasts
];

Migrating From Flash Messages

If you have an existing application using session flash messages, migrating to Sooner toasts is a find-and-replace operation in your controllers:

// Before
session()->flash('success', 'Record saved.');
session()->flash('error', 'Something went wrong.');

// After
Sooner::success('Record saved.');
Sooner::error('Something went wrong.');

The @soonerToasts directive can optionally read legacy flash keys (success, error, warning, info) for backward compatibility during migration — so you can migrate controllers incrementally.

GitHub Repository

Source code and full API documentation on GitHub.

composer require amjadiqbal/laravel-sooner
php artisan vendor:publish --provider="AmjadIqbal\LaravelSooner\SoonerServiceProvider" --tag="config"

Conclusion

Session flash messages were the right solution for their era. Toast notifications are the right solution for today's Laravel applications. Laravel Sooner makes the migration straightforward and maintains the same PHP-first ergonomics Laravel developers expect. If your application still uses bare flash messages, this is the upgrade you have been looking for.