Laravel Toaster Magic is a lightweight, flexible toast library for Laravel projects, with no jQuery, Bootstrap, or Tailwind dependency.
devrabiul/laravel-toaster-magic is a Laravel package for laravel toaster magic is a lightweight, flexible toast library for laravel projects, with no jquery, bootstrap, or tailwind dependency..
It currently has 227 GitHub stars and 101.193 downloads on Packagist (latest version v2.6).
Install it with composer require devrabiul/laravel-toaster-magic.
Discover more Laravel packages by devrabiul
or browse all Laravel packages to compare alternatives.
Last updated
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.
π Try the Live Demo

slide, fade, pop, or bounce.prefers-reduced-motion support.| | 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.
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
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>
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());
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,
]);
Pass a preset to swap the type icon for an animated one. A preset sits on
top of the type β success still owns the colour, the progress bar and how
the toast is announced:
ToastMagic::success('Added to cart', 'Nike Air Max Γ1', [
'preset' => 'cart-add',
]);
success Β· Preset = cart-add Β· Icon = cart Β· Animation = bounce517 presets ship across 11 packs. Enable the ones your project needs:
// config/laravel-toaster-magic.php
'presets' => ['general', 'commerce'], // or 'all', or [] for none
| Pack | Presets | Covers |
|---|---:|---|
| general | 76 | Loading, connectivity, auth, clipboard, preferences, device state |
| commerce | 121 | Carts, orders, payments, shipping, catalogue, promotions, stock |
| saas | 44 | Subscriptions, workspaces, seats, usage, integrations |
| social | 38 | Messages, posts, connections, reviews, moderation |
| devops | 61 | Builds, deploys, source control, infrastructure, incidents |
| media | 36 | Capture, encoding, publishing, playback |
| files | 37 | Documents, storage, backups, scanning |
| health | 28 | Appointments, prescriptions, vitals, lab work |
| travel | 26 | Flights, stays, ground transport, itineraries |
| education | 25 | Courses, lessons, assignments, grading, library |
| crm | 25 | Leads, deals, accounts, calls, forecasting |
Only the packs you list are loaded β a project pays for nothing else. The core runtime ships no presets at all.
Omit preset and every existing call renders exactly as before. An unrecognised
preset is ignored and the toast falls back to its type icon.
For the full list with icons, animations and per-preset examples, see PRESETS.md.
Multi-coloured, with light and dark palettes you can retint per preset or across the set. Geometry is Lucide (ISC), animated with CSS β no Lottie player and no runtime dependency. See colour and why not Lottie.
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
});
// Animated icon preset, layered on top of the type
toastMagic.success({ heading: 'Added to cart', preset: 'cart-add' });
// 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);
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. |
| data-toast-preset | Animated icon preset. An unregistered name is ignored. |
Attribute content is escaped like any other toast text.
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.
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',
]
);
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 |
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.
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',
],

success, error, warning and info, plus avatar toasts, the
custom action button, color mode and every animation option.--toast-magic-box-shadow variable, which you
can override in your own stylesheet.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',
],

#e6eaf2) that blends into the page, a white highlight
and a soft blue-gray shadow.#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.success, error, warning and info, 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..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.
Enable color mode to apply toast-type colors automatically to backgrounds and accents:
return [
'options' => [
'color_mode' => true,
],
];
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 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',
],
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.
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.
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 */ }
}
Built in, no configuration required:
role="alert" (assertive); everything else uses role="status" (polite), so a success message never interrupts what a screen reader is reading.<button> with an accessible name (closeButtonLabel, default "Close notification"). Icons are aria-hidden.pauseOnHover setting, so a toast cannot vanish mid-interaction.timeOut => 0 (globally or per toast) to keep a toast until it is dismissed. Recommended for anything the user must act on.prefers-reduced-motion: reduce every entrance, exit, progress and reflow animation is neutralised; toasts appear and disappear without travel.Colour-mode backgrounds pick their own foreground per type so text stays above the WCAG AA 4.5:1 contrast ratio.
// 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,
];
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.
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.
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.
Please report vulnerabilities privately β see SECURITY.md.
See CHANGELOG.md for a list of notable changes in each release.
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.
This package is open-source software licensed under the MIT License.
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.