Weave 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

Filament Unsaved Changes Modal Laravel Package

azgasim/filament-unsaved-changes-modal

Replaces Filament's browser confirmation dialog with a native Filament modal when leaving a dirty form. Works with SPA and full-page navigation, using the same dirty-state rules as unsavedChangesAlerts(). Requires Filament 5.3.5+ and PHP 8.2+.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Form-abandonment polish. This is a cosmetic but user-visible fix: leaving a dirty form stops showing a jarring, unstyled browser confirm() and shows a Filament-styled Stay/Leave modal. It falls in the "make the admin panel feel like one coherent product" bucket, not the feature bucket.
  • Roadmap sequencing. It is a two-line install gated on ->unsavedChangesAlerts(), so the natural slot is an existing Filament upgrade or quality-of-life sprint where panel providers are already being touched. It is not worth its own release.
  • Build vs. buy. Building this in-house means writing JS interception for both livewire:navigate and full-page same-origin clicks, plus modal open/close by DOM id, plus translations, plus forever-maintenance against Filament upgrades — realistically a day plus carrying cost. Buying is composer require plus two lines. Buy, unless dependency policy blocks it.
  • Scoping the promise. The package replaces the modal only on link navigation within the panel. Reload (F5) and tab-close still use the native browser prompt — that is a browser constraint, not a package gap. Any spec or ticket written against this must say so explicitly, or you will ship a "fixed" bug that users can still reproduce.
  • Prioritization signal. Nobody files a feature request for this; they file "I lost my edits" or "why does this ugly box appear" tickets. If those exist in volume, this is a cheap reduction. If not, it stays backlog.
  • Uniformity as the selling point. Because it registers at the panel level, it lands identically on every resource, relation manager, and custom page. Hand-rolling a per-form beforeLeave hook gives you inconsistent coverage and a maintenance tail — that asymmetry is the actual product argument here.
  • Demo and stakeholder-facing surfaces. If the panel is shown in sales demos or used by non-technical ops/support/content staff, this is a small credibility upgrade. For a purely internal, engineer-only tool, the value approaches zero.

When to Consider This Package

Good fit when:

  • You run a Filament 5 panel on ^5.3.5 (the floor is deliberate — earlier 5.x has a known XSS advisory) and PHP 8.2+.
  • You either already call ->unsavedChangesAlerts() or are willing to. Without it forms never register as dirty, no modal appears, and there is nothing in the logs — the single most common misconfiguration.
  • Your panel users are non-technical and/or work in long forms (orders, settings, multi-step custom pages) where losing state matters.
  • You want the behavior everywhere at once, with no per-resource opt-in.
  • Your locale set overlaps en, de, ckb, fr — those ship today, and translations are the only way to change the copy.
  • You value a small blast radius: it swaps UI only, reuses Filament's own dirty-state rules, and can be reverted by deleting one line.

Look elsewhere when:

  • You are on Filament 4.x or older — the plugin pins 5.3.5+ and there is no backport.
  • Your real problem is losing work, not the dialog. This is cosmetic; the durable fix is autosave or persisted drafts. Do not let this package stand in for that decision.
  • Dependency policy forbids low-adoption packages in a production admin surface (see risk note below). The code is small and MIT — vendor or fork it and own it; you lose little.
  • You only need it on one or two forms — panel-wide registration is the whole design, and you would be paying the dependency for a fraction of the surface.
  • You need to customize interception logic beyond the five fluent setters, translations, and the data-skip-unsaved-changes-modal escape hatch.
  • You need server-side guarantees around unsaved state (audit of abandoned edits, session recovery). Out of scope entirely.

Adoption terms if you proceed: pin the exact version in composer.lock, publish only the translations (avoid publishing views unless you must — a published view drifts from upstream markup), and treat the data-skip-unsaved-changes-modal attribute as a short deliberate list (cancel/discard links, logout, help-desk) rather than a default. Add one browser assertion per critical flow — dirty a form, click a nav link, assert the modal id appears, assert Leave actually reaches the target URL — because composer test covers the package, not your integration.

How to Pitch It (Stakeholders)

To executives (one paragraph): A small, free, MIT-licensed add-on for our admin panel that replaces the browser's blocking "are you sure you want to leave" popup with a modal that matches our product's look, and gives users a clear Stay/Leave choice. Cost is roughly one engineering hour plus a test; it is reversible by removing a single line. It reduces a recurring class of "I lost my work" support tickets and makes the panel look finished to anyone who sees it. It does not fix data loss on reload — autosave remains a separate, larger decision.

To engineering (the detail that matters):

  • One composer require, then both ->unsavedChangesAlerts() and ->plugin(FilamentUnsavedChangesModalPlugin::make()) on the panel. Dropping either one produces silence, not an error.
  • The entire public API is one short, final plugin class — five fluent setters for width, icon, icon color, and the two button colors, plus MODAL_DOM_ID. No config file (removed as a breaking change in 1.0.0); theme via the fluent chain so the visual contract is one reviewable diff.
  • All user-facing copy lives under navigation.* in translations; publish and edit as normal app copy rather than patching views.
  • Interception covers SPA (livewire:navigate) and same-origin full-page links. data-skip-unsaved-changes-modal on a link or any ancestor exempts a cluster via closest(...).
  • Debug surprises in the hook Blade file (the JS that opens/closes by DOM id), not in the plugin class.

Risk to state plainly, not bury: 12 stars, 0 dependents, a single maintainer, and a Filament-major-coupled version constraint. That is fine for a UI-only swap of this size, but classify it as a forkable utility, not infrastructure: pin the version, keep the escape hatch minimal, and put it on the list to re-evaluate at the next Filament major. If the project stalls, taking over a few hundred MIT lines is a bounded afternoon — which is exactly why the buy decision is safe here.

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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package