edulazaro/wiretoast
Framework-agnostic toast notifications for Laravel with optional Livewire helper and Alpine support. Pure CSS themes (no Tailwind/Bootstrap), zero JS deps, 5 types, 7 positions, dark mode, progress bar, titles/messages, group mode, and easy custom theming via CSS variables.
To begin using wiretoast in a Laravel/Livewire project, follow these minimal steps:
Install the Package
composer require edulazaro/wiretoast
Load Assets
For Vite projects (recommended):
Import the CSS and JS in resources/js/app.js and resources/css/app.css:
import '@wiretoast/js/wiretoast.js';
import '@wiretoast/css/wiretoast.css';
Add the component to your layout (e.g., resources/views/layouts/app.blade.php):
<x-wiretoast />
For non-Vite projects: Publish assets and inject them in Blade:
php artisan vendor:publish --tag=wiretoast-assets
<x-wiretoast :assets="true" />
Trigger Your First Toast
In a Livewire component, use the $this->notify() helper:
$this->notify('Success! Your changes were saved.', 'success');
Or in Alpine.js:
<button @click="$dispatch('notify', { message: 'Hello!', type: 'info' })">
Show Toast
</button>
Verify
Open your browser’s dev tools (F12) and check the rendered toasts in the DOM under .wt-toast.
First Use Case: Display a success toast after a form submission in Livewire.
// In your Livewire component
public function submitForm()
{
$this->validate([...]);
// Save logic...
$this->notify('Form submitted successfully!', 'success');
}
$this->notify() in Livewire components for server-side triggered toasts.
$this->notify('Operation failed.', 'error');
$this->notify('Warning!', 'warning', [
'position' => 'bottom-center',
'timeout' => 8000,
'progress' => true,
]);
$this->notify('Duplicate entry.', 'error', true); // Legacy group mode
// OR
$this->notify('Duplicate entry.', 'error', ['group' => true]);
$dispatch in Alpine.js for frontend-triggered toasts.
<button @click="$dispatch('notify', {
title: 'Update',
message: 'Profile updated at ' + new Date().toLocaleTimeString(),
type: 'success',
position: 'top-right'
})">
Update Profile
</button>
window.notify() for non-Alpine contexts.
window.notify('Direct JS toast!', 'info');
<x-wiretoast theme="glass" mode="dark" default-position="bottom-right" />
/* Custom theme */
[data-wt-theme="brand"] .wt-toast {
--wt-bg: #2d3748;
--wt-text: #ffffff;
}
<x-wiretoast theme="brand" />
// vite.config.js
export default defineConfig({
resolve: {
alias: {
'@wiretoast': path.resolve(__dirname, 'vendor/edulazaro/wiretoast/resources'),
},
},
});
public/vendor/wiretoast/ and inject via Blade.Use the notify helper in controllers for non-Livewire responses (requires manual JS dispatch):
return redirect()->route('dashboard')->with([
'toast' => ['message' => 'Redirect success!', 'type' => 'success']
]);
Then dispatch in a Blade script:
@if(session('toast'))
<script>
window.notify({{ json_encode(session('toast')) }});
</script>
@endif
Sync Livewire and Alpine toasts by dispatching Alpine events in Livewire:
// Livewire component
public function syncToast()
{
$this->dispatch('notify-alpine', message: 'Synced toast!');
}
<!-- Alpine -->
<script>
window.addEventListener('notify-alpine', (e) => {
$dispatch('notify', {
message: e.detail.message,
type: 'info'
});
});
</script>
Use wire:submit to show toasts on validation errors:
<form wire:submit="save">
<!-- Fields -->
@error('email') <span class="error">{{ $message }}</span> @enderror
<button type="submit">Save</button>
</form>
@script
window.addEventListener('livewire:submit', (e) => {
if (e.detail.success) {
$dispatch('notify', { message: 'Saved!', type: 'success' });
}
});
@endscript
Intercept API responses in Livewire and notify users:
// Livewire component
public function fetchData()
{
try {
$data = Http::get('...')->json();
$this->notify('Data fetched successfully!', 'success');
} catch (\Exception $e) {
$this->notify($e->getMessage(), 'error');
}
}
Asset Injection Conflicts
:assets="true" in non-Vite projects causes missing CSS/JS.<x-wiretoast :assets="true" /> <!-- Non-Vite -->
<x-wiretoast /> <!-- Vite -->
Livewire Hydration Mismatches
wire:ignore on the toast container or clear toasts in mount():
public function mount()
{
$this->clearToasts(); // Hypothetical; use Alpine/Livewire events instead
}
Dark Mode Overrides
.dark) may conflict with prefers-color-scheme.mode="dark" or mode="light" in the component to override OS preferences.Progress Bar Timing
timeout is set to 0 (persistent toast).timeout is a positive integer (e.g., 5000) for progress bars to work.Group Mode Quirks
type or message differs slightly (e.g., whitespace).Vite HMR Delays
?t=... cache-busting queries in development.Inspect Toast State Use browser dev tools to check:
.wt-toast classes, data attributes (data-wt-*).:root scope to test themes.$dispatch events in Alpine or window.notify calls.Disable Auto-Dismiss
Temporarily set timeout: 0 to debug persistent toasts:
window.notify('Debug toast', 'info', { timeout: 0 });
Log Notifications Add a debug listener in Alpine to log toast payloads:
<script>
window.addEventListener('notify', (e) => {
console.log('Toast payload
How can I help you explore Laravel packages today?