Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bvfi-dev's avatar

[Livewire 3] Custom Notification Banner Component doesn't work/re-render

The Problem

Im trying to build a custom notification banner that will trigger instantly on top of the screen, whenever its triggered. The session() doesn't work the way I want it to, so I can't use it. I believe the component is simply not re-rendering. I have put a /Debugbar::addMessage() in the components and all of the variables are set correctly, there is a REQUEST each time I click the button and the data changes. However, the view doesn't. The :class is not applied at all, the banner has no background color (The element exists in the HTML, I checked in Chrome, it just doesn't want to update.

The Code

I have a Helper:

class NotifyUser
{
    public static function sendBanner(string $message, int $type = 2, int $timeout = 3): void
    {
        Banner::notify($message, $type, ($timeout *1000));
    }
}

Then I have a Banner Livewire component:

namespace App\Livewire\Notifications;
use Livewire\Component;
class Banner extends Component
{
    public $message, $type, $timeout, $visible = false;
    public function render()
    {
        return view('livewire.notifications.banner');
    }
    public static function notify($message, $type, $timeout): void
    {
        $instance = new static();
        if($instance->_showNotification($message, $type, $timeout)) {
            \Debugbar::addMessage($instance);
            \Debugbar::addMessage($message);
            \Debugbar::addMessage($type); //It prints the message and type = 1
            $instance->dispatch('send-notification');
        }
    }
    private function _showNotification($message, $type, $timeout): bool
    {
        $this->message = $message;
        $this->type = $type;
        $this->timeout = $timeout;
        $this->visible = true;
        return isset($this->message);
    }
}

The view for the component:

<div class="w-full flex justify-center">
    <div x-data="{ show: $wire.entangle('visible'), type: $wire.entangle('type'), timeout: $wire.entangle('timeout') }"
         x-show="show"
         x-init="if (show) {
                     setTimeout(() => { show = false }, timeout);
                 }
          "
         x-on:send-notification="console.log('Sending notification')"
         class="z-50 fixed top-0 m-4 text-white p-4 rounded w-5/6"
         :class="{'bg-red-500': type === 0, 'bg-green-500 ': type === 1, 'bg-blue-500 ': type === 2}">
        {{ $message }}
    </div>
</div>

Its placed in the default layout app.blade.php like:

</head>
<body class="font-sans antialiased">
{{--<x-banner />--}}
@livewire('notifications.banner')

Its called like:

<button wire:click="sendNotification(true)"> Test</button>
public function sendNotification($isSuccess): void
{
    if($isSuccess) NotifyUser::sendBanner(__('flashes.object.updated'), 1);
}

Livewire

The more I work in Livewire, the more I realize how much it sucks for learning, because it makes no god damn sense sometimes and its really frustrating to work in it. Maybe I should've went with Vue. The documentation says I can do x-on:send-notification="console.log('Sending notification')" and AlpineJS would work, so when I do this, I dont see a 'Sending notification' in the console, eventhough a new request was made. The result from \Debugbar::addMessage($instance); is:

App\Livewire\Notifications\Banner {#1694 ▼
  #__id: null
  #__name: null
  #listeners: []
  #attributes: ? Livewire\Features\SupportAttributes\AttributeCollection
  #withValidatorCallback: null
  #rulesFromOutside: []
  #messagesFromOutside: []
  #validationAttributesFromOutside: []
  +message: "Anzeige aktualisiert!"
  +type: 1
  +timeout: 3000
  +visible: true
}

The documentation also says I can bind the Livewire and AlpineJS variables, however it doesnt work.

0 likes
1 reply
bvfi-dev's avatar

Bumping this, as I still have no solution nor idea how to approach and what might be preventing it from working. The code is there, and its logic is pretty simple: Using a Helper show a notification to the user depending on parameters. I cannot use session->flash() as its not triggered instantly. I just want a simple pop-down that displays a notification and I cant even get that working in Livewire. I think the issue is with Livewire 3 and AlpineJS, something drastically has changed and now my x-on:send-notification="console.log('Sending notification')" doesn't even get triggered, but the Debugbars do:

if($instance->_showNotification($message, $type, $timeout)) {
            \Debugbar::addMessage($instance);
            \Debugbar::addMessage($message);
            \Debugbar::addMessage($type); //It prints the message and type = 1
            $instance->dispatch('send-notification');
        }

I had an issue where:

x-on:livewire-upload-start="uploading = true;console.log('Started')"
             x-on:livewire-upload-finish="uploading = false"
             x-on:livewire-upload-cancel="uploading = false"
             x-on:livewire-upload-error="uploading = false"
             x-on:livewire-upload-progress="progress = $event.detail.progress"

Arent properly being triggered. I wil lswitch it with document.addEventListener('livewire-upload-start', () => { and see what happens.

Please or to participate in this conversation.