cocosmos/filament-sticky-save-bar
Filament v5 plugin that shows a sticky save bar when a form has unsaved changes, keeping actions visible on long pages. Auto-hides after save or undo, works with all field types, respects sidebar, supports dark mode, translations, and per-page opt-out.
composer require cocosmos/filament-sticky-save-bar
PanelServiceProvider:
public function panel(Panel $panel): Panel
{
return $panel
->plugin(StickySaveBarPlugin::make());
}
Scenario: You have a multi-tabbed edit form (e.g., EditUser) where users frequently forget to save after scrolling through sections. The sticky bar ensures visibility of save actions without requiring users to scroll back to the top.
Steps:
users/1/edit).Automatic Detection:
wire:model changes, wire:submit).ShowOn::Dirty or ShowOn::DirtyAlways).ShowOn::Dirty or ShowOn::Always).User Interaction:
wire:submit handler.users index).State Management:
wire:submit.success).EditRecord or Form pages. The plugin works out of the box with standard Livewire forms.wire:submit for submission. The plugin relies on Filament’s form lifecycle events.HasStickySaveBarDisabled trait on specific pages:
class EditShortForm extends EditRecord
{
use HasStickySaveBarDisabled;
}
StickySaveBarPlugin::make()
->enabled(fn () => auth()->user()->isAdmin());
StickySaveBarPlugin::make()
->withDiscard() // Add "Discard changes"
->withSaveAndClose() // Add "Save & Close"
->withCancel(false); // Remove "Cancel"
resources/views/vendor/filament-sticky-save-bar.blade.php).use Cocosmos\FilamentStickySaveBar\Enums\Position;
StickySaveBarPlugin::make()
->position(Position::Top); // Pins to the top
fixed positioning with inset-inline-end: 0 (Tailwind).php artisan vendor:publish --tag=sticky-save-bar-translations
StickySaveBarPlugin::make()
->label('Guardar cambios') // Spanish
->saveLabel('Guardar');
@extends('filament::components.action-group')
@section('actions')
{{ $this->getSaveButton() }}
{{ $this->getCancelButton() }}
<x-filament::button
wire:click="customAction"
color="gray"
>
Custom Action
</x-filament::button>
@endsection
StickySaveBarWillShow, StickySaveBarWillHide) by extending the plugin class.Dirty State Scope:
wire:submit-enabled form on the page. If you have nested forms, disable the plugin for the parent form using HasStickySaveBarDisabled.Modal Conflicts:
Modal component (not custom JS modals). The plugin detects Filament modals via its internal state.Sidebar Overlap:
inset-inline-end: 0 (Tailwind). If issues persist, check for custom CSS overriding Filament’s default spacing.Form Reset Behavior:
wire:ignore or custom JS).reset event or use the wire:model binding to reset fields. The plugin listens to Filament’s reset event.Custom Form Fields:
input events or update wire:model bindings. Example:
<x-your-custom-field
wire:model="field.name"
@change="dispatch('input')"
/>
Check Dirty State:
wire:model updates. Dirty state is tracked via these events.mount() or updated() methods to verify state changes:
public function mount()
{
$this->dispatch('log', ['StickySaveBar: Form mounted']);
}
Verify Plugin Registration:
PanelServiceProvider:
public function panel(Panel $panel): Panel
{
return $panel
->plugins([
// Other plugins...
])
->plugin(StickySaveBarPlugin::make());
}
Inspect CSS:
fixed positioning is being overridden. Look for !important rules or custom styles targeting .filament-sticky-save-bar.Test Edge Cases:
ShowOn::Dirty vs. ShowOn::DirtyAlways:
ShowOn::Dirty (default): Bar appears only if the native save button is scrolled out of view. Use this for most cases to avoid clutter.ShowOn::DirtyAlways: Bar appears as soon as the form is dirty, regardless of scroll position. Useful for very long forms where users might forget to save.Button Visibility:
redirect() helper. If your app uses custom navigation (e.g., SPA-like routing), disable it and add your own logic.Dark Mode:
dark: variants. If issues arise, ensure your Filament theme supports dark mode and that no custom CSS overrides the bar’s background/color.Translations:
How can I help you explore Laravel packages today?