An open API service indexing awesome lists of open source software.

https://github.com/mustafakhaleddev/filament-modal-notifications

Render any Filament notification as a blocking modal
https://github.com/mustafakhaleddev/filament-modal-notifications

Last synced: 2 months ago
JSON representation

Render any Filament notification as a blocking modal

Awesome Lists containing this project

README

          

# Filament Modal Notifications

Render any Filament notification as a blocking modal by chaining one method: `->asModal()`. Multiple modal notifications fired in the same request are queued one at a time — the user dismisses one and the next slides in, no stacking.

Everything else you already know about Filament notifications (title, body, icon, color, actions, `danger()`/`success()`/`warning()`/`info()`) carries over unchanged.

## Requirements

- PHP 8.2+
- Laravel 11+ / 13
- Filament 4 or 5

## Features

- **One-line opt-in** — chain `->asModal()` onto any `Notification::make()` call. No new classes to learn.
- **Queued** — multiple modal notifications show one at a time, dismissal advances to the next.
- **Auto-added Close button** — if the developer didn't declare actions, the modal gets a "Close" button in its footer so it's always dismissible.
- **Respects your actions** — if you declare `->actions([...])`, those render in the footer instead.
- **Conditional** — `->asModal($isCritical)` is a no-op when the condition is false, so the notification sends as a regular toast.
- **Independent of the toast tray** — modal notifications never briefly flash as toasts; they use a dedicated session key and Livewire event.
- **Plugin-level defaults** — set the default modal width, closable behavior, and close button label per panel.

## Installation

```bash
composer require wezlo/filament-modal-notifications
```

Register the plugin on your panel so the Livewire component mounts at the page footer:

```php
use Wezlo\FilamentModalNotifications\FilamentModalNotificationsPlugin;

public function panel(Panel $panel): Panel
{
return $panel
->plugins([
FilamentModalNotificationsPlugin::make(),
]);
}
```

Optionally publish the config:

```bash
php artisan vendor:publish --tag=filament-modal-notifications-config
```

## Quick Start

```php
use Filament\Notifications\Notification;

Notification::make()
->title('Changes not saved')
->body('Your unsaved edits will be lost if you leave this page.')
->danger()
->asModal()
->send();
```

That's it. On the next Livewire cycle, a modal opens with the title, body, and a default Close button. Regular toasts still work exactly as before — only notifications with `->asModal()` go through the modal pipeline.

## Usage

### With custom actions

The notification's actions render in the modal footer:

```php
use Filament\Actions\Action;
use Filament\Notifications\Notification;

Notification::make()
->title('Delete this order?')
->body('This cannot be undone.')
->warning()
->actions([
Action::make('cancel')->label('Cancel')->color('gray')->close(),
Action::make('delete')->label('Delete')->color('danger')
->action(fn () => $this->record->delete())
->close(),
])
->asModal()
->send();
```

When any action's `->close()` is invoked (or the user clicks X / Esc / clicks outside if closable), the queue advances to the next pending modal notification.

### Conditional modal

`->asModal(false)` leaves the notification as a normal toast:

```php
Notification::make()
->title($wasCritical ? 'Error' : 'Saved')
->asModal($wasCritical)
->send();
```

### Queued — multiple in one request

```php
Notification::make()->title('Step 1 complete')->asModal()->send();
Notification::make()->title('Step 2 complete')->asModal()->send();
Notification::make()->title('Step 3 complete')->asModal()->send();
```

The user sees one modal at a time in FIFO order. Each dismissal advances to the next. When the queue is empty the modal closes.

### Panel-level defaults

```php
use Filament\Support\Enums\Width;
use Wezlo\FilamentModalNotifications\FilamentModalNotificationsPlugin;

->plugins([
FilamentModalNotificationsPlugin::make()
->defaultWidth(Width::Large)
->defaultClosable(false) // block Esc / click-away / X — require an explicit action
->defaultCloseButtonLabel('Dismiss'),
])
```

| Method | Type | Default | Description |
|---|---|---|---|
| `defaultWidth(Width\|string)` | enum/string | `md` | Modal width (`sm`, `md`, `lg`, `xl`, `2xl`, …, `screen`) |
| `defaultClosable(bool)` | bool | `true` | Whether the modal can be dismissed via X, Esc, or click-away |
| `defaultCloseButtonLabel(string)` | string | `Close` | Label for the auto-added Close action |

## Default Config File

```php
// config/filament-modal-notifications.php
return [
'default_width' => 'md',
'default_closable' => true,
'default_close_label' => 'Close',
];
```

## How It Works

- **`->asModal()` is a macro** registered on `Filament\Notifications\Notification` in the service provider. It returns a `Wezlo\FilamentModalNotifications\ModalNotification` — a subclass that overrides `send()` to push into a dedicated session key (`filament.modal-notifications`) instead of the default `filament.notifications`.
- **A custom dehydrate hook** dispatches the `modalNotificationsSent` Livewire event when the modal session key has pending notifications (same pattern Filament uses for its toast tray).
- **A Livewire component** (`Wezlo\FilamentModalNotifications\Livewire\ModalNotifications`) mounts at `PanelsRenderHook::BODY_END`. It listens for `modalNotificationsSent`, drains the session key into an in-component queue, and renders the first pending notification through ``. When the user dismisses the modal (X, Esc, click-away, or any action chained with `->close()`), the component advances to the next queued notification.
- **No toast flash** — because modal notifications use a separate session key, the default toast tray never sees them.

## License

MIT