Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Toaster Laravel Package

nawasara/toaster

Lightweight Alpine-powered toast notifications for Laravel and Livewire. Add one component to your layout and trigger success/error/warning/info toasts from JavaScript, Livewire, or session flash. Configurable position, optional progress bar, dark-mode aware.

View on GitHub
Deep Wiki
Context7

Implementation Patterns

Livewire Workflows (Continued)

  • Real-time toasts (no redirect): Requires nawasara/ui package. Dispatch events from Livewire:
    use Nawasara\Ui\Livewire\Concerns\HasBrowserToast;
    
    class MyComponent extends Component {
        use HasBrowserToast;
    
        public function save() {
            // ...
            $this->toast('success', 'Saved in real-time!');
        }
    }
    
    The toaster listens for toast events via Alpine.js:
    // Auto-handled by <x-nawasara-toaster::script />
    

3. Laravel Flash Integration

  • Auto-loading flash messages: The package checks for session('toast') on page load and renders it automatically. Override defaults:
    session()->flash('toast', [
        'type' => 'warning',
        'message' => 'Custom flash message',
        'position' => 'bottom-center',
    ]);
    
  • Fallback for non-toast flashes: Use middleware to redirect legacy flashes (e.g., status) to toasts:
    // app/Http/Middleware/RedirectFlashToToast.php
    public function handle($request, Closure $next) {
        if ($request->session()->has('status')) {
            $request->session()->flash('toast', [
                'type' => 'info',
                'message' => $request->session()->get('status'),
            ]);
            $request->session()->forget('status');
        }
        return $next($request);
    }
    

4. Customization Patterns

  • Global configuration: Override Alpine store defaults via a custom script:
    document.addEventListener('alpine:init', () => {
        Alpine.store('toaster', {
            extend: {
                defaultDuration: 7000,
                defaultPosition: 'top-center',
            },
        });
    });
    
  • Dynamic content: Pass HTML or variables from Laravel:
    session()->flash('toast', [
        'type' => 'info',
        'message' => '<strong>User</strong> created: <span class="font-mono">@entertainly</span>',
    ]);
    
    The toaster escapes HTML by default; use message_html for raw HTML:
    session()->flash('toast', [
        'type' => 'info',
        'message_html' => '<strong>User</strong> created: <span class="font-mono">@entertainly</span>',
    ]);
    

5. Advanced: Extending Toast Types

  • Add a new toast type (e.g., question) by extending the Alpine store:
    Alpine.store('toaster', {
        extend: {
            types: {
                question: {
                    icon: '❓',
                    class: 'bg-blue-500 text-white',
                },
            },
        },
    });
    
    Then use it:
    window.Toast.question('Confirm action?');
    

6. Integration with Forms/Validation

  • Livewire validation feedback:
    protected $rules = ['email' => 'required|email'];
    public function updated($property) {
        $this->validateOnly($property);
        if ($this->validate($property)) {
            $this->toast('success', 'Email is valid!');
        } else {
            $this->toast('error', 'Invalid email.');
        }
    }
    
  • Laravel Form Requests:
    public function withValidator($validator) {
        $validator->after(function ($validator) {
            if ($validator->errors()->any()) {
                session()->flash('toast', [
                    'type' => 'error',
                    'message' => 'Please fix errors below.',
                ]);
            }
        });
    }
    

7. Testing Strategies

  • Unit test triggers:
    // Test flash integration
    $response = $this->post('/submit', []);
    $response->assertRedirect();
    $this->assertSessionHas('toast');
    
  • Feature test toasts:
    // In a Livewire test
    Livewire::test('MyComponent')
        ->call('save')
        ->assertToast('success', 'Saved!');
    
    (Note: Requires custom assertions or Alpine store inspection.)
  • Alpine store inspection:
    // Debug toasts in browser console
    console.log(Alpine.store('toaster').toasts);
    

Gotchas and Tips

Pitfalls

  1. Flash Message Overwrite:

    • Issue: Multiple session()->flash('toast') calls overwrite each other.
    • Fix: Use arrays for cumulative toasts:
      session()->push('toast.queue', ['type' => 'info', 'message' => 'New item']);
      
      (Requires custom Alpine store logic to handle queues.)
  2. Livewire Event Race Conditions:

    • Issue: Real-time toasts (HasBrowserToast) may fire out of order or duplicate.
    • Fix: Use unique IDs or debounce events:
      // In Alpine script
      let lastToastId = 0;
      window.addEventListener('toast', (e) => {
          if (e.detail.id !== lastToastId) {
              lastToastId = e.detail.id;
              // Show toast
          }
      });
      
  3. Alpine.js Conflicts:

    • Issue: Namespace collisions if multiple Alpine stores are used.
    • Fix: Scope the toaster store:
      Alpine.store('toaster', { ... });
      
      (Avoid global Alpine.store('toaster') if another package uses it.)
  4. Dark Mode Quirks:

    • Issue: Custom dark mode classes may not apply if the host app uses a non-standard theme.
    • Fix: Extend the Alpine store’s dark mode logic:
      Alpine.store('toaster', {
          extend: {
              darkModeClass: 'dark:bg-gray-800', // Override
          },
      });
      
  5. Session Timeout:

    • Issue: Flash toasts disappear if the session expires mid-redirect.
    • Fix: Use session()->putNow() or ensure session lifetime is sufficient.
  6. Livewire Component Isolation:

    • Issue: Toasts from nested Livewire components may not render.
    • Fix: Dispatch events at the root level or use wire:ignore carefully.

Debugging Tips

  1. Inspect Alpine Store:

    console.log(Alpine.store('toaster'));
    
    • Check toasts, config, and events for state.
  2. Check for JavaScript Errors:

    • Ensure <x-nawasara-toaster::script /> loads before triggers (e.g., window.Toast).
    • Verify Alpine.js is loaded (check window.Alpine).
  3. Livewire Event Debugging:

    • Listen for events in the browser console:
      window.addEventListener('toast', (e) => console.log(e.detail));
      
  4. Flash Data Inspection:

    • Dump session data to verify flash payloads:
      dd(session()->all());
      
  5. CSS Conflicts:

    • Use browser dev tools to inspect toast elements for overridden styles.
    • Add a unique class to the toaster component for scoping:
      <x-nawasara-toaster::toaster class="my-toaster" />
      
      .my-toaster .toast { /* Custom styles */ }
      

Configuration Quirks

  1. Default Position:

    • The position attribute on <x-nawasara-toaster::toaster /> overrides the global default.
    • Valid positions: top-left, top-center, top-right, center, bottom-left, bottom-center, bottom-right, bottom-start, bottom-end.
  2. Duration Handling:

    • duration: 0 disables auto-dismiss.
    • Negative values or null may cause unexpected behavior (validate inputs).
  3. Progress Bar:

    • The progress bar is enabled by default. Disable via Alpine store:
      Alpine.store('toaster', {
          extend: {
              showProgress: false,
          },
      });
      
  4. Mobile Responsiveness:

    • The toaster uses Tailwind’s responsive prefixes (e.g., md:top-0). Override breakpoints if needed:
      Alpine.store('toaster', {
          extend: {
              mobileBreakpoint: 'sm', // Default: 'md'
          },
      });
      

Extension Points

  1. Custom Toast Actions:
    • Add buttons or links to toasts by extending the template:
      Alpine.store('toaster', {
          extend: {
              toastTemplate: `
                  <div x-data="{ open: true }" class="toast">
                      <div class="message" x-text="message"></div>
                      <button @click="open = false">Dismiss</button>
                      <slot></slot
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky