devrabiul / laravel-toaster-magic
Laravel Toaster Magic is a lightweight, flexible toast library for Laravel projects, with no jQuery, Bootstrap, or Tailwind dependency.
Package info
github.com/devrabiul/laravel-toaster-magic
pkg:composer/devrabiul/laravel-toaster-magic
Requires
- php: ^8.0
- illuminate/cache: ^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0
- illuminate/config: ^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0
- illuminate/filesystem: ^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0
- illuminate/session: ^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0
- illuminate/support: ^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0 || ^13.0
Requires (Dev)
- orchestra/testbench: ^8.0 || ^9.0 || ^10.0 || ^11.0
- pestphp/pest: ^2.0 || ^3.0
README
π Laravel Toaster Magic β v2.5
Laravel Toaster Magic is a lightweight, dependency-free toast notification package for Laravel with Livewire v3 & v4 support.
Laravel Toaster Magic provides elegant, fully customizable toast notifications for Laravel applications β with zero dependency on jQuery, Bootstrap, or Tailwind CSS. It works out of the box with Livewire, supports multiple modern themes, and is simple enough to drop into any project in minutes.
π Live Demo
π Try the Live Demo
β¨ Features
- π₯ Easy to Use β Simple, intuitive API with support for both static and fluent syntax.
- π RTL Support β Full compatibility with right-to-left languages.
- π Dark Mode β Built-in dark mode support via a single HTML attribute.
- π¨ 9+ Themes β iOS, Neon, Glassmorphism, Material, Minimal, Neumorphism, Neumorphic, Compact, and Default.
- π Configurable Spacing & Typography β Global padding, gaps and font sizes that work with any theme.
- ποΈ Entrance/Exit Animations β Choose how toasts enter and leave:
slide,fade,pop, orbounce. - πͺ Smooth Stack Reflow β Remaining toasts glide into place (FLIP) when one is added or dismissed.
- πΌοΈ Avatar Toasts β Render an image in place of the type icon for notification-style toasts.
- β‘ Livewire Ready β Livewire v3 & v4 via a thin event bridge over the same runtime the standard build uses.
- π Safe by Default β Toast text is escaped, URLs are protocol-checked, and HTML is opt-in per toast. See Security.
- βΏ Accessible β Live-region announcements, a labelled close button, Escape to dismiss, pause on focus, and full
prefers-reduced-motionsupport. - β Zero Dependencies β No jQuery, Bootstrap, or Tailwind required.
β Requirements
| Supported | Covered by CI | |
|---|---|---|
| PHP | 8.0 β 8.5 | 8.1 β 8.5 |
| Laravel | 8 β 13 | 10 β 13 |
| Livewire | v3, v4 (optional) | β |
Laravel 8 and 9 are supported and expected to work β the package targets PHP 8.0 and uses only long-stable Illuminate APIs β but they are not in the CI matrix. Their Testbench majors pin PHPUnit 9 while Pest 2+ requires PHPUnit 10, so covering them would mean maintaining a second test-tooling major for two end-of-life framework versions. If you hit a problem on Laravel 8 or 9, please open an issue.
π¦ Installation
Install the package via Composer:
composer require devrabiul/laravel-toaster-magic
Publish the config file (optional):
php artisan vendor:publish --tag=toast-magic-config
Assets are copied into
public/packages/devrabiul/laravel-toaster-magicautomatically on the first request after an install or upgrade β you do not normally need to publish them.If you install from a branch (
dev-main) or a path repository, Composer has no version to compare against, so publish them explicitly after each update:php artisan vendor:publish --tag=toast-magic-assets --force
βοΈ Basic Setup
Add the stylesheet inside your <head> tag and the scripts just before the closing </body> tag:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Page Title</title> {!! ToastMagic::styles() !!} </head> <body> <!-- Your Content --> {!! ToastMagic::scripts() !!} </body> </html>
π§βπ» Usage
1. Controller Usage
Trigger toast notifications from your controllers using the ToastMagic facade:
use Devrabiul\ToastMagic\Facades\ToastMagic; public function store() { // Simple message ToastMagic::success('Successfully Created'); // Message with description ToastMagic::success('Success!', 'Your data has been saved!'); // With custom options ToastMagic::success('Success!', 'Your data has been saved!', [ 'showCloseBtn' => true, 'customBtnText' => 'View Record', 'customBtnLink' => 'https://example.com', 'timeOut' => 10000, // Optional: override the auto-dismiss time (ms) for this toast only 'showDuration' => 300, // Optional: override the show animation delay (ms) for this toast only ]); return back(); }
Available toast types: success, info, warning, error
You can also pass a validation MessageBag directly β its messages are flattened into a single toast, one per line:
ToastMagic::error($validator->errors());
πΌοΈ Avatar / notification-style toasts
Pass an avatar URL to render an image in place of the type icon β ideal for "new message" / "new follower" style notifications:
ToastMagic::info('New message', 'Hey, are you free to chat?', [ 'avatar' => $user->avatar_url, ]);
2. JavaScript Usage
The runtime creates a single shared instance as window.toastMagic. Use it directly β do not call new ToastMagic(), which would build a second instance competing for the same container.
// Options object (recommended) toastMagic.success({ heading: 'Success!', description: 'Your data has been saved!' }); toastMagic.error({ heading: 'Error!', description: 'Something went wrong.' }); toastMagic.info({ heading: 'New message', description: 'Hey, are you free to chat?', showCloseBtn: true, customBtnText: 'Reply', customBtnLink: '/messages/42', avatar: '/avatars/42.png', timeOut: 10000, // 0 = stay until dismissed showDuration: 300, html: false, // true renders the text as HTML β you own its safety }); // Programmatically dismiss all visible toasts toastMagic.clear(); // or toastMagic.dismissAll();
Positional signature (still supported for backward compatibility):
toastMagic.success('Heading', 'Description', showCloseBtn, customBtnText, customBtnLink, timeOut, showDuration, avatar);
2a. HTML Data Attributes
Any element carrying data-toast-type raises a toast when clicked β no JavaScript required:
<button data-toast-type="success" data-toast-heading="Saved" data-toast-description="Your changes are live." data-toast-close-btn data-toast-btn-text="View" data-toast-btn-link="/records/42" >Save</button>
| Attribute | Purpose |
|---|---|
data-toast-type |
success, error, warning or info. Anything else falls back to info. |
data-toast-heading |
Toast heading. Defaults to Notification. |
data-toast-description |
Optional body text. |
data-toast-close-btn |
Presence of the attribute shows the close button. |
data-toast-btn-text |
Action button label. |
data-toast-btn-link |
Action button URL (protocol-checked). |
data-toast-avatar |
Image URL shown in place of the type icon. |
Attribute content is escaped like any other toast text.
3. Livewire Support (v3 & v4)
Enable Livewire support in your config file:
// config/laravel-toaster-magic.php return [ 'options' => [ // your toast options... ], 'livewire_enabled' => true, ];
Dispatch toast notifications from any Livewire component:
// With full options $this->dispatch('toastMagic', status: 'success', title: 'User Created', message: 'The user has been successfully created.', options: [ 'showCloseBtn' => true, 'customBtnText' => 'View Profile', 'customBtnLink' => 'https://example.com', ], ); // Simple dispatch $this->dispatch('toastMagic', status: 'info', title: 'Heads Up', message: 'Your session will expire soon.' );
Supported status values: success, info, warning, error
Backward Compatibility: Both
showCloseBtnandcloseButtonoption keys are supported in Livewire events. If both are provided,showCloseBtntakes priority.
4. Alternative & Fluent Syntax
ToastMagic supports both a quick static method and a fluent dispatch style.
Static (Quick):
use Devrabiul\ToastMagic\Facades\ToastMagic; ToastMagic::success('Operation Successful'); ToastMagic::error('Something went wrong');
Fluent (Advanced):
ToastMagic::dispatch()->success( 'User Created', 'The user has been successfully created.', [ 'showCloseBtn' => true, 'customBtnText' => 'View Profile', 'customBtnLink' => 'https://example.com', ] );
π Position Options
Control where toasts appear on screen using the positionClass config option:
| Value | Position |
|---|---|
toast-top-start |
Top left |
toast-top-end |
Top right (default) |
toast-top-center |
Top center |
toast-bottom-start |
Bottom left |
toast-bottom-end |
Bottom right |
toast-bottom-center |
Bottom center |
π¨ Themes
ToastMagic includes 9 built-in themes. Set your preferred theme in config/laravel-toaster-magic.php:
return [ 'options' => [ "theme" => "default", // See options below ], ];
| Theme | Description |
|---|---|
default |
Clean, classic look |
material |
Material Design β flat and bold |
ios |
Apple-style notifications with backdrop blur |
glassmorphism |
Heavy blur, semi-transparent, modern aesthetic |
neon |
Dark background with glowing borders β ideal for dark UIs |
minimal |
Clean design with colored left-side accent |
neumorphism |
Soft UI with extruded shadow styling |
neumorphic |
Soft UI, refined β dual-direction shadows, raised controls, recessed progress groove |
compact |
Minimal and dense β tight spacing, small footprint, no decorative effects |
For a full theme preview, see THEMES.md.
π§· Compact
A smaller, denser take on the default toast for interfaces where a notification should stay out of the way. The surface is deliberately plain β a solid background, a hairline border and a slim progress bar, with no gradients, blur or glass effects. Everything that costs space is pulled in: the padding around the toast, the gap between the icon and the text, the gap between the title and the description, and the space around the close and action controls, which share a single row instead of being spread down the full height of the toast.
// config/laravel-toaster-magic.php 'options' => [ 'theme' => 'compact', ],
- Footprint β a 320px track instead of the default 370px, with roughly half the vertical padding. On small screens it falls back to the same full-width track as every other theme.
- Supported toast types β
success,error,warningandinfo, plus avatar toasts, the custom action button, color mode and every animation option. - Shadow β a single hairline lift on the shared
--toast-magic-box-shadowvariable, which you can override in your own stylesheet.
πͺΆ Neumorphic
A soft-UI theme where the toast reads as an object extruded from the same material as the page behind it. Depth comes from a dual-direction shadow pair β a light highlight from the top-left and a soft dark shadow from the bottom-right β plus a hairline inner bevel, instead of borders or gradients. The icon puck, close button and action button are raised controls that lift on hover and press into the surface on click, and the progress bar sits in a groove carved into the bottom edge.
// config/laravel-toaster-magic.php 'options' => [ 'theme' => 'neumorphic', ],
- Light mode β a cool off-white surface (
#e6eaf2) that blends into the page, a white highlight and a soft blue-gray shadow. - Dark mode β a dedicated treatment rather than an inversion: a soft charcoal surface
(
#2c2f36) on a deeper charcoal page, where the shadow carries the depth and the highlight is reduced to a faint light edge. Semantic accents are muted so nothing glows. - Supported toast types β
success,error,warningandinfo, plus avatar toasts. The surface stays monochromatic for every type; only the icon, the progress fill and the focus ring pick up the semantic accent. - Customizing β the theme is driven by CSS variables scoped to
.toast-container.theme-neumorphic(--tm-neu-surface,--tm-neu-shadow-light,--tm-neu-shadow-dark,--tm-neu-radius,--tm-neu-distance,--tm-neu-blur,--tm-neu-accent). Override any of them in your own stylesheet to match your app's surface:
.toast-container.theme-neumorphic { --tm-neu-surface: #eef0f5; --tm-neu-radius: 1.5rem; }
Note:
neumorphicis a separate theme from the originalneumorphismβ selecting it does not change the look ofneumorphismor any other theme.
π Color Mode
Enable color mode to apply toast-type colors automatically to backgrounds and accents:
return [ 'options' => [ 'color_mode' => true, ], ];
π Gradient Mode
Enable gradient mode to apply subtle gradients to toast backgrounds:
return [ 'options' => [ "gradient_enable" => true, ], ];
Note: Gradient mode works best with the
default,material, andneonthemes.
π Spacing
Spacing is a global option: it works with every theme, not just compact.
return [ 'options' => [ 'spacing' => [ 'enable' => true, 'container' => '10px 12px', // Padding inside the toast 'icon_gap' => '8px', // Icon <-> content 'content_gap' => '2px', // Title <-> description 'close_gap' => '6px', // Content <-> close/action controls ], ], ];
| Key | Controls |
|---|---|
enable |
Whether the values below are applied at all |
container |
The toast's internal padding (any valid CSS padding value) |
icon_gap |
The gap between the icon (or avatar) and the text |
content_gap |
The gap between the title and the description |
close_gap |
The gap between the content and the close/action controls |
Set 'enable' => false and every theme falls back to its own spacing. The same happens per value:
omit a key (or set it to null) and only that one falls back β so you can retune the padding while
leaving the theme's gaps alone.
Want the toast even tighter than compact?
'spacing' => [ 'enable' => true, 'container' => '6px 8px', 'icon_gap' => '5px', 'content_gap' => '0px', 'close_gap' => '4px', ],
π€ Typography
Also global, and shaped exactly like spacing:
return [ 'options' => [ 'typography' => [ 'enable' => true, 'title_size' => '14px', 'description_size' => '13px', ], ], ];
| Key | Controls |
|---|---|
enable |
Whether the values below are applied at all |
title_size |
The toast title font size |
description_size |
The description/message font size |
title_weight |
(optional) The title font weight |
description_weight |
(optional) The description font weight |
line_height |
(optional) Line height for the title and description |
The last three are optional on purpose: leave them out and each theme keeps its own weight and line height while the sizes still follow your config.
How it works: both sections are resolved into CSS custom properties (
--tm-space-container,--tm-font-title-size, β¦) that are set on the toast container. Every theme declares its own value as that property's fallback, so an unset property is a no-op and a set one overrides every theme β no!importantoverrides, and no theme-specific config. You can also set the same properties yourself in a stylesheet if you prefer CSS over config.
ποΈ Animations
Choose how toasts enter and leave the screen using the animation config option:
return [ 'options' => [ 'animation' => 'slide', // default, slide, fade, pop, bounce ], ];
| Value | Effect |
|---|---|
default |
Slide in from the toast's position (default) |
slide |
Position-aware slide with its own easing |
fade |
Fade in/out with no movement |
pop |
Scale up from slightly smaller, with a soft overshoot |
bounce |
Slide in with a springy overshoot |
Smooth stack reflow: When a toast is added or dismissed, the remaining toasts glide smoothly into their new positions (using the FLIP technique) instead of jumping. This honors the user's
prefers-reduced-motionsetting and requires no configuration.
π Dark Mode
Add theme="dark" to your <body> tag:
<body theme="dark">
Every shipped theme has a dark treatment. neon is dark by design and looks the same either way; neumorphism keeps its light soft-UI surface deliberately and pins its own text colour so it stays readable.
Using Tailwind or prefers-color-scheme instead? The stylesheet keys off the theme attribute, so mirror your existing signal onto <body>:
// Tailwind's .dark class on <html> const sync = () => document.body.toggleAttribute('theme', document.documentElement.classList.contains('dark')) || document.body.setAttribute('theme', document.documentElement.classList.contains('dark') ? 'dark' : ''); sync();
/* β¦or follow the OS setting directly */ @media (prefers-color-scheme: dark) { body:not([theme]) { /* copy the dark tokens you want here */ } }
βΏ Accessibility
Built in, no configuration required:
- Announcements β toasts are announced through persistent live regions. Errors use
role="alert"(assertive); everything else usesrole="status"(polite), so a success message never interrupts what a screen reader is reading. - Close button β a real
<button>with an accessible name (closeButtonLabel, default "Close notification"). Icons arearia-hidden. - Keyboard β Esc dismisses the most recent toast, so dismissal never depends on the close button being enabled.
- Focus β tabbing into a toast pauses its dismiss timer, regardless of the
pauseOnHoversetting, so a toast cannot vanish mid-interaction. - Timing β set
timeOut => 0(globally or per toast) to keep a toast until it is dismissed. Recommended for anything the user must act on. - Reduced motion β under
prefers-reduced-motion: reduceevery entrance, exit, progress and reflow animation is neutralised; toasts appear and disappear without travel. - Touch targets β close buttons are at least 24Γ24 px, and 32Γ32 px on coarse pointers.
Colour-mode backgrounds pick their own foreground per type so text stays above the WCAG AA 4.5:1 contrast ratio.
βοΈ Full Configuration Reference
// config/laravel-toaster-magic.php return [ 'options' => [ 'escape_html' => true, // Escape toast text. Leave this on. 'closeButton' => true, 'positionClass' => 'toast-top-end', 'preventDuplicates' => false, 'showDuration' => 300, 'timeOut' => 5000, // 0 = stay until dismissed 'stagger' => 800, // Gap between consecutive queued toasts (ms) 'maxVisible' => 15, // Most toasts on screen at once; 0 = no limit 'theme' => 'default', // default, material, ios, glassmorphism, neon, minimal, neumorphism, neumorphic, compact 'gradient_enable' => false, 'color_mode' => false, 'pauseOnHover' => true, // Keyboard focus always pauses the timer 'animation' => 'default', // default, slide, fade, pop, bounce // Accessible names 'closeButtonLabel' => 'Close notification', 'containerLabel' => 'Notifications', // Global spacing β 'enable' => false uses each theme's own spacing. 'spacing' => [ 'enable' => true, 'container' => '10px 12px', 'icon_gap' => '8px', 'content_gap' => '2px', 'close_gap' => '6px', ], // Global typography β 'enable' => false uses each theme's own typography. // 'title_weight', 'description_weight' and 'line_height' are optional. 'typography' => [ 'enable' => true, 'title_size' => '14px', 'description_size' => '13px', ], ], // One event bridge serves both Livewire v3 and v4. 'livewire_enabled' => false, // CSP nonce for the inline <script> blocks (or use ToastMagic::nonce()). 'csp_nonce' => null, // null auto-detects. Set 'public' if your document root is the project // root, or '' to force no prefix on published asset URLs. 'asset_path_prefix' => null, ];
π Security
Message content is escaped by default
Toast text is written to the DOM with textContent, so passing user-supplied input straight into a toast is safe:
ToastMagic::success('Welcome, ' . $user->name . '!'); // safe, no e() needed
Multi-line messages still work β newlines become real <br> elements after escaping:
ToastMagic::info("First line\nSecond line");
If you genuinely need markup in a toast, opt in per toast:
ToastMagic::success('<strong>Saved</strong>', null, ['html' => true]);
With ['html' => true] you own the safety of that string β escape any user input inside it yourself. There is also a global escape_html => false switch, but turning it off makes every toast render raw HTML and is not recommended.
URLs are validated by protocol
customBtnLink and avatar are parsed and checked against a protocol allowlist:
| Field | Allowed |
|---|---|
customBtnLink |
http:, https:, mailto:, tel:, plus relative (/path) and fragment (#id) URLs |
avatar |
http:, https:, plus relative URLs |
Anything else β javascript:, data:, vbscript: β is rejected. A rejected link falls back to #; a rejected avatar falls back to the type icon.
URLs are applied with setAttribute() rather than being interpolated into an HTML string, so a value containing quotes cannot create additional attributes.
Content Security Policy
The package emits two small inline <script> blocks. Under a CSP that disallows 'unsafe-inline', give them a nonce:
{!! ToastMagic::nonce($nonce)->scripts() !!}
or set csp_nonce in the config when the value is known at config time. External assets are plain <script src> / <link rel="stylesheet"> and need no exception.
Reporting
Please report vulnerabilities privately β see SECURITY.md.
π Changelog
See CHANGELOG.md for a list of notable changes in each release.
π€ Contributing
Contributions are welcome! Please fork the repository, make your changes, and open a pull request. For bug reports or feature requests, open an issue on GitHub.
π License
This package is open-source software licensed under the MIT License.
π± Treeware
This package is Treeware. If you use it in production, we ask that you buy the world a tree to thank us for our work. By contributing to the Treeware forest you'll be creating employment for local families and restoring wildlife habitats.
π¬ Contact & Links
- π GitHub: devrabiul/laravel-toaster-magic
- π Live Demo: laravel-toaster-magic.rixetbd.com
- π Packagist: packagist.org/packages/devrabiul/laravel-toaster-magic
- π§ Email: devrabiul@gmail.com

