azgasim/filament-unsaved-changes-modal
Installation
composer require azgasim/filament-unsaved-changes-modal
Publish the config (optional):
php artisan vendor:publish --provider="AzGasim\FilamentUnsavedChangesModal\FilamentUnsavedChangesModalServiceProvider" --tag="config"
Register the Plugin
Add to your app/Providers/Filament/AdminPanelProvider.php (or app/Providers/Filament/TenantPanelProvider.php):
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
\AzGasim\FilamentUnsavedChangesModal\FilamentUnsavedChangesModalPlugin::make(),
]);
}
First Use Case
Test by editing a record in a Filament form (e.g., resources/PostResource). Attempt to navigate away—you’ll see the modal instead of the browser’s default prompt.
Form Integration
The plugin automatically detects "dirty" forms (unsaved changes) in Filament’s built-in forms (Form, Table, EditForm, CreateForm). No manual setup is required for standard Filament forms.
Customization
Override default modal behavior via config (config/filament-unsaved-changes-modal.php):
'modal' => [
'title' => 'You have unsaved changes',
'description' => 'Are you sure you want to leave? Your changes will be lost.',
'confirm_button' => 'Leave Anyway',
'cancel_button' => 'Stay on Page',
],
SPA vs. Traditional Navigation
livewire:navigate (e.g., clicking breadcrumbs or table rows).<a href="/posts">).Excluding Resources/Pages Disable the modal for specific resources/pages:
public function panel(Panel $panel): Panel
{
return $panel->plugins([
\AzGasim\FilamentUnsavedChangesModal\FilamentUnsavedChangesModalPlugin::make()
->excludeResources([PostResource::class])
->excludePages([SettingsPage::class]),
]);
}
Custom Form Handling For non-standard forms (e.g., custom Livewire components), manually trigger the modal:
use AzGasim\FilamentUnsavedChangesModal\Facades\FilamentUnsavedChangesModal;
// In your Livewire component
protected function handleNavigation()
{
if ($this->hasChanges()) {
FilamentUnsavedChangesModal::show();
return;
}
// Proceed with navigation
}
Browser Prompts Still Trigger
F5) or closing the tab cannot be intercepted by this plugin—browser-native prompts will still appear. This is a limitation of the browser’s behavior.SPA Navigation Edge Cases
livewire:navigate with custom logic (e.g., wire:navigate), ensure the modal is triggered before the navigation event. Example:
document.addEventListener('livewire:navigate', (e) => {
if (e.detail.url && !confirmUnsavedChanges()) {
e.preventDefault();
}
});
The plugin handles this automatically for standard Filament navigation, but custom JS may need adjustments.Form State Detection
$this->reset() in Livewire), the modal may not trigger as expected. Use $this->resetValidation() or $this->fill() instead to preserve state.Nested Modals
Modal component). The plugin uses Filament’s modal stack, which may cause rendering issues.Modal Not Showing?
wire:key (required for Livewire forms). If missing, add it to your form component:
<x-filament::form wire:key="your-form-key">
panel() and no excludeResources is blocking your resource.Styling Issues
resources/css/filament/filament-unsaved-changes-modal.css:
.filament-unsaved-changes-modal {
--wp-gap: 1rem;
/* Customize as needed */
}
Logging Enable debug mode in config:
'debug' => env('FILAMENT_UNSAVED_CHANGES_DEBUG', false),
Check Laravel logs for initialization errors.
Custom Modal Content Override the modal view by publishing assets:
php artisan vendor:publish --tag="filament-unsaved-changes-modal-views"
Edit resources/views/vendor/filament-unsaved-changes-modal/modal.blade.php.
Event Listeners Listen for modal events (e.g., when a user confirms/cancels):
use AzGasim\FilamentUnsavedChangesModal\Events\UnsavedChangesModalShown;
UnsavedChangesModalShown::listen(function ($event) {
info('Modal shown for form: ' . $event->formId);
});
Conditional Behavior Dynamically enable/disable the modal per form:
public function getUnsavedChangesModal(): bool
{
return $this->someCondition;
}
Add this method to your Livewire form component. The plugin will respect it if present.
How can I help you explore Laravel packages today?