oriceon/toastr-5-laravel
Laravel 5 wrapper for the toastr.js notification library. Flash success, info, warning, and error toast messages from your controllers and display them in Blade views with a simple facade, helper functions, and publishable configuration.
Install
composer require oriceon/toastr-5-laravel
Oriceon\Toastr\ToastrServiceProvider. On older versions register it in config/app.php and add the alias:
'Toastr' => Oriceon\Toastr\Facades\Toastr::class,
php artisan vendor:publish --provider="Oriceon\Toastr\ToastrServiceProvider"
This creates config/toastr.php (toastr.js options, asset URLs, enable/disable flag).Wire it into your layout once
In your master Blade layout, just before </body>:
{!! Toastr::render() !!}
That call flushes any queued notifications into an inline <script> block. It must come after jQuery and toastr.js are loaded — check whether the package is emitting those tags for you via its config, or whether your layout already bundles them (see Gotchas).
Where to look first
config/toastr.php — default position, timeout, close button, progress bar, and whether the package injects jQuery/toastr assets.Toastr facade methods: success, info, warning, error, add, clear, render.Toastr::render() and that it sits below the JS includes.First use case: flash-on-redirect
public function store(StorePostRequest $request)
{
$post = Post::create($request->validated());
Toastr::success('Post created.', 'Success');
return redirect()->route('posts.index');
}
The message is queued in the session; the redirect renders the layout, render() emits the JS, and toastr fires on page load. That redirect-flash loop is 90% of real-world usage — get that working end-to-end before exploring anything else.
Controller flash (the default pattern). Call Toastr::* immediately before return redirect(...) or return back(). Nothing is emitted on the current response; it's deferred to the next full page render.
Form Request / validation feedback. Validation errors already redirect with $errors; add a toast in the same flow:
if ($validator->fails()) {
Toastr::error('Please fix the highlighted fields.', 'Validation failed');
return back()->withErrors($validator)->withInput();
}
Or centralize it in App\Exceptions\Handler::render() for ValidationException, guarded by !$request->expectsJson().
Global exception toasts. In app/Exceptions/Handler.php:
public function render($request, Throwable $e)
{
if (! $request->expectsJson() && $this->shouldReport($e)) {
Toastr::error('Something went wrong. Please try again.', 'Error');
}
return parent::render($request, $e);
}
Keep the user-facing string generic; log the detail. Avoid firing toasts for 404s or auth redirects unless you actually want them.
AJAX / JSON responses. Toastr::render() is server-rendered on the next document load, so it does nothing for XHR that never reloads the layout. Two workable approaches:
toastr.success(...) yourself on the JS side.eval-free inject it via a small helper that appends the <script> — useful if all your toasts must be configured server-side.Guard queuing with $request->expectsJson() so you don't leave stale messages piling up in the session for API calls.
Service/observer layer. For domain events (e.g. OrderShipped), don't scatter Toastr:: calls in listeners — inject a small Notifier service that wraps the facade. It keeps controllers thin and gives you one place to swap transport (toast vs. email vs. Slack) later:
class Notifier
{
public function success(string $msg, string $title = 'Success'): void
{
Toastr::success($msg, $title);
}
}
Per-message options. Most versions accept an options array on each call, merged over the config defaults:
Toastr::warning('Session expiring in 2 minutes.', 'Heads up', [
'timeOut' => 0,
'extendedTimeOut' => 0,
]);
Reach for this sparingly — a consistent global default (via config/toastr.php) reads better than toasts that each behave differently.
Composition with other flash data. If you already have a session()->flash('status', ...) convention, wrap both in a helper so you never ship a page that shows the same message twice (banner + toast).
Testing. Assert the session payload rather than the rendered HTML, or fake the facade:
Toastr::shouldReceive('success')->once();
For feature tests that assert page content, either disable rendering in the test environment or assert against the session key the package uses (session()->get(...)) — inspect the package's Toastr class to confirm the key name for your version.
Duplicate jQuery / toastr.js. The config typically controls whether the package emits <script> tags for jQuery and toastr.js (often via CDN URLs). If your layout already loads either, you'll get a second copy — jQuery in particular will clobber plugins and silently break other JS. Disable the package's asset injection and load them yourself, or vice versa, but pick one. This is the #1 cause of "nothing happens" reports.
render() placement. It must appear after jQuery + toastr.js in the document, exactly once per page. Putting it in <head> yields toastr is not defined. Calling it twice double-fires every queued message, because the first call usually clears the queue.
Session-backed queue is sticky. Messages are flashed into the session and only consumed when render() runs. Any page that doesn't render (error pages, JSON endpoints, a layout you forgot to update, emails) leaves messages queued — they'll resurface later, sometimes on a completely unrelated page. If you see "phantom toasts," audit every response path that bypasses your main layout.
AJAX does nothing, by design. Redirects and full reloads only. If your SPA-style app never reloads, this package is the wrong tool — use client-side toastr calls fed by your JSON responses.
Config caching. php artisan config:cache after editing config/toastr.php, or your changes appear to have no effect in production. Also remember config isn't loaded when the package is disabled/absent.
HTML in messages. Toasts are JSON-encoded into the emitted script; if you need links or bold text, you'll likely have to disable toastr's escapeHtml per message and sanitize the input yourself. Rendering user-supplied HTML into a toast is an XSS vector — treat it as {!! !!}-level dangerous.
Deep-merge behavior. Per-message options arrays often replace rather than merge nested keys. If you pass ['timeOut' => 5000] and notice your config positionClass reverting, you're hitting a shallow merge — repeat the defaults you care about or update the config instead.
Ordering and volume. newestOnTop plus a rapid succession of calls (e.g. looping validation errors) can stack a dozen toasts. Batch into one message, or call Toastr::clear() before queuing the summary.
Maintenance reality check. Last release 2024 but the package targets Laravel 5. Auto-discovery works via extra.laravel, so it generally installs on modern Laravel, but verify the facade alias and config publish tag against the installed version — and if you hit friction, the underlying surface is small enough (Toastr::render() emitting a script block) that hand-rolling a Blade partial with session flash is a 20-line fallback with no supply-chain risk.
Debugging. Dump Toastr::render() in a controller before returning to see exactly what script would be emitted, and inspect the session store after a redirect to confirm the queue was populated. If the script looks right but no toast appears, the problem is almost always script-load order or a jQuery conflict — open the console before touching the package config.
How can I help you explore Laravel packages today?