Back to blog

Filament

written by Aziz Gasim

Filament: Unsaved changes as a modal instead of the browser dialog

The filament-unsaved-changes-modal plugin swaps the native confirm() prompt for a Filament modal while keeping Filament’s dirty-state behaviour—SPA-friendly and customizable.

Filament: Unsaved changes as a modal instead of the browser dialog

Filament: Unsaved changes as a modal instead of the browser dialog

When you edit a form in a Filament panel and try to leave without saving, Filament’s unsavedChangesAlerts() feature kicks in—and the browser often shows the classic window.confirm dialog. It works, but it feels disconnected from the rest of the UI: no shared dark mode, no brand colours, none of the panel’s visual language.

I built filament-unsaved-changes-modal to address that: the same dirty-state rules as Filament, but the confirmation is a Filament modal with “Stay” and “Leave” actions (copy is customizable via translations).

What changes for users

  • In-panel navigation (links in the body, same origin): you get a Filament modal instead of the browser popup.

  • Closing the tab or reloading the page: the native browser prompt still applies. That is intentional; a panel modal cannot reliably replace those flows.

The plugin supports Filament SPA (livewire:navigate) and standard full-page navigation.

Installation

Install via Composer (PHP 8.2+, Filament ^5.3.5—see the CVE note in the README):

composer require azgasim/filament-unsaved-changes-modal

Panel setup

You need unsavedChangesAlerts() and the plugin together—the package only replaces the confirmation UI, not Filament’s unsaved-change detection.

use AzGasim\FilamentUnsavedChangesModal\FilamentUnsavedChangesModalPlugin;

return $panel
    // … your existing configuration …
    ->unsavedChangesAlerts()
    ->plugin(FilamentUnsavedChangesModalPlugin::make());

You can also register FilamentUnsavedChangesModalPlugin::make() inside ->plugins([...]) alongside your other plugins.

Customization without forking the package

  • Width, icon, colours for the modal and buttons: methods such as modalWidth(), modalIcon(), modalIconColor(), stayButtonColor(), and leaveButtonColor()—allowed values follow Filament conventions (width strings like the Width enum, colours are your panel colour keys).

  • Copy (heading, description, button labels): translations only—publish with the filament-unsaved-changes-modal-translations tag. The package ships English and German out of the box.

  • Blade markup when you really need it: publish views (filament-unsaved-changes-modal-views). If you change the modal DOM id, keep it in sync with the plugin constant and the script hook (documented in the README).

To skip the prompt for specific links, add data-skip-unsaved-changes-modal on the <a> or any ancestor element.

Links

Issues and feedback are welcome on GitHub—if this saves you a few awkward browser dialogs in production, I’d love to hear it.