๐ Laravel Toaster Magic โ v2.5.0 Release Notes
Release date: 2026-08-23
Type: Minor release โ one deliberate behavioral change, see the Upgrade Guide below
v2.5.0 is a "Safe by default" release, and the largest one so far. It fixes a cross-site
scripting vulnerability, makes message escaping the default, and adds the things people kept
asking for: a compact theme, and global spacing and typography options that work with any
theme. Under the surface it also removes a per-request filesystem loop that could serve 404s for the
package's own CSS, and consolidates the two JavaScript runtimes into one.
โ ๏ธ Please read the Security Fixes section below. If you pass user-supplied values to a
toast โ a name, an avatar URL, a link โ you were exposed to XSS in v2.4 and earlier.
โจ Highlights
- ๐ XSS vulnerability fixed (high severity) โ reachable through
avatar,customBtnLink,
Livewire event options anddata-toast-btn-link. - ๐ก๏ธ Message content is now escaped by default, with an explicit
['html' => true]opt-in. - ๐งท New
compacttheme โ smaller, denser, deliberately plain. - ๐ Global
spacingandtypographyโ padding, gaps and font sizes, configurable per app. - โฟ Accessibility overhaul โ announcements that actually announce, Esc to dismiss,
WCAG AA contrast fixes, real touch targets. - โก No more per-request asset churn โ publishing converges instead of re-copying every request.
- ๐งช 148 JavaScript tests + a reproducible asset build where there was previously neither.
- ๐ฆ ~140 KB published payload, down from ~1.6 MB.
๐ Security Fixes
Cross-site scripting in sanitizeUrl() โ high severity
The URL sanitiser validated only the prefix of a URL and never escaped quotes, and its result was
interpolated into an innerHTML string. A value such as:
/a" onerror="alert(1)
passed the prefix check, closed the src/href attribute, and injected an event handler.
It was reachable through the avatar option โ the README's own example passed a user profile
field โ as well as customBtnLink, Livewire event options and data-toast-btn-link.
URLs are now parsed with new URL(), checked against a protocol allowlist (http:, https:,
mailto:, tel:; javascript: and data: are rejected), and applied with setAttribute() โ which
makes attribute breakout structurally impossible rather than merely filtered.
Escaping is now the default
Headings, descriptions and action button labels are written with textContent. Newlines still
become real <br> elements, inserted after escaping, so multi-line messages keep working.
// Escaped โ safe with any user input
ToastMagic::success('Welcome, ' . $user->name);
// Opt in per toast when you genuinely mean HTML
ToastMagic::success('Welcome, <strong>' . e($user->name) . '</strong>', null, ['html' => true]);Also hardened
- Config values are validated against allowlists.
theme,positionClassandanimation
outside the known sets fall back to their defaults instead of being concatenated into output. - The emitted JSON is hardened with
JSON_HEX_TAG/HEX_AMP/HEX_APOS/HEX_QUOT, so a
</script>inside any value cannot terminate the script block early. - Content-Security-Policy support โ
ToastMagic::nonce($nonce)or thecsp_nonceconfig value
applies a nonce to both inline script blocks. There was previously no way to run this package
under a policy without'unsafe-inline'.
๐ What's New
๐งท The Compact theme
// config/laravel-toaster-magic.php
'options' => [
'theme' => 'compact',
],
A smaller, denser take on the default toast, for interfaces where a notification should stay out of
the way. Padding, the icon-to-text gap, the title/description gap and the space around the controls
are all pulled in; the close and action buttons share a single row; the progress bar is slimmed to
2px; and the track narrows from 370px to 320px.
Deliberately plain โ a solid surface, a hairline border and semantic accents, with no gradients,
blur or glass effects. Supports every toast type, avatar toasts, color mode, animations, dark mode
and RTL.
๐ Global spacing and typography
Two new sections that work with any theme, not just compact:
'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
],
'typography' => [
'enable' => true,
'title_size' => '14px',
'description_size' => '13px',
// Optional: 'title_weight', 'description_weight', 'line_height'
],
],Each value is resolved into a CSS custom property set on the toast container, and every theme
declares its own value as that property's fallback. So:
'enable' => falseโ that whole section falls back to the active theme's own values.- An omitted or
nullvalue โ that value alone falls back, while the rest still apply. - A value you set โ overrides every theme, with no
!importantwars and no theme-specific config.
Want the toast tighter than compact ships? Turn the numbers down:
'spacing' => [
'enable' => true,
'container' => '6px 8px',
'icon_gap' => '5px',
'content_gap' => '0px',
'close_gap' => '4px',
],You can also set the same properties directly in a stylesheet if you prefer CSS over config:
.toast-container {
--tm-space-container: 6px 8px;
--tm-font-title-size: 14px;
}๐งฐ Smaller additions
| Option | What it does |
|---|---|
['html' => true]
| Renders that toast's text as HTML (per toast) |
escape_html
| Global escaping switch โ off is not recommended |
stagger
| Delay between consecutive queued toasts. Was a hardcoded 1000 ms; now 400 ms |
maxVisible
| Most toasts on screen at once (default 6); the oldest is dismissed to make room. 0 = no limit
|
closeButtonLabel
| Accessible name for the close button |
containerLabel
| Accessible name for the toast region |
csp_nonce
| CSP nonce for the inline script blocks |
asset_path_prefix
| Explicit asset path, replacing the old IP-address heuristic |
โฟ Accessibility
- Announcements now work. Toasts were given
role="alert"and inserted with their content
already present โ which assistive technology frequently does not announce at all. Text is now
written into persistent live regions: polite for success/info/warning, assertive for errors. - The close button has an accessible name (default "Close notification"); it previously
announced as just "button". Decorative icons arearia-hidden. - Esc dismisses the most recent toast, so dismissal no longer depends on the close
button being enabled. - Keyboard focus pauses the dismiss timer, regardless of
pauseOnHover. timeOut => 0keeps a toast until dismissed (WCAG 2.2.1).prefers-reduced-motionis honoured throughout โ entrances, exits, the iOS bounce and the
progress bars, not just the stack reflow.- WCAG AA contrast failures fixed. Color mode forced white text onto every accent: white on the
amber measured 1.63:1 and on the cyan 1.96:1, against a 4.5:1 requirement. Warning and info
now take a dark foreground. - Close-button touch targets are at least 24ร24 px, and 32ร32 px on coarse pointers.
- Added dark-mode treatments for
glassmorphismandminimal.
๐ Notable Fixes
- Assets are no longer deleted and re-copied on every request. When the installed version could
not be resolved โ adev-*constraint, a branch alias, a path repository โ the check treated
"unknown" as "republish" and never converged. Every request re-copied the whole asset directory,
and concurrent requests served 404s for the package's own CSS out of the gap. Publishing is now
atomic and converges. composer.lockis no longer read on every request.- Published configs now receive new options. Previously the defaults loaded only when no
published config existed, silently withholding every option added after you published yours. - The runtime now reads its configuration. The config object was emitted after the runtime
<script>, so theme, position and close-button settings all stayed on their built-in defaults. showCloseBtnworks server-side โ documented since v2.2 while onlycloseButtonwas read.vendor:publish --tag=toast-magic-assetsexists โ documented for several releases without the
tag ever being registered.- The
slideanimation exists โ it was offered in the config with no CSS behind it. - The progress bar tracks the real dismiss time instead of a hardcoded 3s, and pauses with the
timer. - Asset URLs no longer branch on the client's IP address, which reported
127.0.0.1in
production behind any reverse proxy. toast-top-endno longer left-aligns on small screens.- Heading-only toasts no longer leave blank space under the title โ the text block stretched to
the icon's height and pinned the title to the top, most visible onioswith its 38px icon puck. data-toast-typeis validated โ any truthy property name (constructor,show,clear) was
previously invoked, throwing an uncaughtTypeError.
๐ง Changed
- One JavaScript runtime. The Livewire build's 343-line hand-maintained copy had already drifted
from the standard build in four places. It is removed; Livewire now loads the shared runtime
plus a ~90-line event bridge, and tests assert both paths produce byte-identical markup. - Removed the dead
livewire_versionconfig key โ nothing ever read it. One bridge serves both
Livewire v3 and v4. MessageBagflattening uses newlines instead of<br>. With escaping on, a literal<br>
would display as text. This changes the string stored in the session, not what renders.- Marketing images moved out of
assets/intoart/. They were being copied into every
consuming application's public directory โ 1.5 MB of the 1.6 MB published. The payload is now
~140 KB. useVite()andnonce()return$thisfor chaining.- The leaked global
.position-relativeutility โ a Bootstrap name โ is now
.toast-magic-relative. - Declared previously implicit dependencies on
illuminate/config,illuminate/session,
illuminate/filesystemandilluminate/cache. - Removed the
versionfield fromcomposer.jsonso the git tag is authoritative.
๐งช Quality
- 148 JavaScript tests covering rendering, escaping, URL sanitising, timers, the data-attribute
API, the Livewire bridge and accessibility. The runtime holds essentially all of this package's
behaviour and previously had no tests at all. - A reproducible asset build โ
npm run buildregenerates the minified stylesheet, and
npm run build:checkfails CI if the committed file drifts from the source. - ESLint, plus CI jobs for the JavaScript suite, the build check and a PHP 8.0 syntax gate.
- CI now covers the declared floor (PHP 8.0 / Laravel 8) rather than starting at PHP 8.1 /
Laravel 10 while advertising lower.
๐งฉ Compatibility
| Requirement | Supported |
|---|---|
| PHP | 8.0 โ 8.5 |
| Laravel | 8 โ 13 |
| Livewire | v3 & v4 |
โฌ๏ธ Upgrade Guide
composer update devrabiul/laravel-toaster-magic
php artisan vendor:publish --tag=toast-magic-assets --forceRepublishing is required โ both the CSS and the JS changed.
1. Toast text containing HTML now renders as text
This is the one behavioral change likely to be noticed, and it is deliberate: the previous default
turned any user-supplied value into an XSS hole. If a call intentionally passed markup, opt in:
// Before (v2.4) โ HTML was rendered
ToastMagic::success('Saved <strong>successfully</strong>');
// After (v2.5) โ opt in explicitly
ToastMagic::success('Saved <strong>successfully</strong>', null, ['html' => true]);Search your codebase for toast calls containing <. Plain-text messages need no changes.
2. The new spacing/typography defaults are enabled
spacing and typography ship enabled, and slightly tighter than the historical default
theme (10px 12px padding instead of 1.25rem; a 2px title/description gap instead of 4px). Published
configs are merged over the packaged defaults, so this applies on upgrade too.
To keep every theme's original spacing and font sizes exactly as they were in v2.4:
'options' => [
'spacing' => ['enable' => false],
'typography' => ['enable' => false],
],3. If you install from a branch or path repository
Auto-publishing no longer treats an unresolvable version as "republish". Run the
vendor:publish command above after each update. Tagged releases are unaffected.
4. If you referenced .position-relative or livewire_version
The utility class is now .toast-magic-relative, and the livewire_version config key has been
removed โ nothing ever read it, so you can simply delete it from your published config.
๐ Thanks
Thanks to everyone using and reporting issues on Laravel Toaster Magic. If it helps you in
production, consider planting a tree. ๐ฑ
Full changelog: see CHANGELOG.md.