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 Undo Toast Laravel Package

hoceineel/filament-undo-toast

A Laravel Filament package that adds undoable toast notifications, letting users instantly reverse destructive actions like deletes. Customize messages, durations, and actions to make admin workflows safer and more forgiving.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install the package with Composer and follow its README for Filament panel/plugin registration (or service-provider auto-discovery). There is no config file to learn upfront; almost everything is configured on the action itself.
  • If your UI is not English, publish the package translations or add your own undo-toast::undo-toast.models.{Model} keys. The package ships 23 locales and reuses Filament's terminology, so you usually only need keys for your own models.
  • Start with the most common case: a Filament resource delete action. Swap Filament's DeleteAction for the package's undo-enabled delete action (class/alias per README) and trigger a delete. You should get one toast — not one from Filament plus one from the package — with an Undo affordance and a mod+z shortcut.
  • Then decide whether you need relation restoration. Soft deletes restore themselves; hard deletes need either HasUndoableRelations on the model or an explicit ->restoreRelations([...]) on the action.
  • Verify the happy path end-to-end: delete a record, undo from the toast, then undo with mod+z after selecting rows for a bulk action. Also delete a record where no undo entry is created (e.g. policy/condition blocks it) and confirm Filament's normal "Deleted" notification still appears.

Implementation Patterns

Undo-enabled delete actions

Use the package action wherever you currently use DeleteAction, including table row actions and bulk actions. Keep Filament's confirmation modal; the undo toast happens after the fact.

// Resource table
UndoableDeleteAction::make(),

// Bulk
BulkActionGroup::make([
    UndoableDeleteAction::make(),
]),

Notification replacement semantics

By default the undo toast replaces Filament's success notification for that action. If you have customised successNotification() or successNotificationTitle(), those are kept and Filament's notification is used instead. Turn replacement off globally for an action, or decide per action with a closure:

UndoableDeleteAction::make()
    ->replaceSuccessNotification(false);

UndoableDeleteAction::make()
    ->replaceSuccessNotification(fn ($action) => auth()->user()->isAdmin());

Remember Filament's notification still shows whenever no undo entry is created — that is the fallback path, not a bug.

Restoring relations on hard delete

Declare relations once on the model:

class Post extends Model implements HasUndoableRelations
{
    // declare the relations the package should restore (see the contract for the method name)
    public function undoableRelations(): array
    {
        return ['comments', 'tags'];
    }
}

Or override per action:

UndoableDeleteAction::make()
    ->restoreRelations([
        Post::class => ['comments', 'tags'],
    ]);

Supported relation types are BelongsToMany (pivot rows including pivot columns), HasMany, HasOne, MorphMany and MorphOne. Rows are inserted only when missing, inside the same transaction as the model restore.

Translations for model labels

Default English labels resolve from undo-toast::undo-toast.models.{Model}, then from your app's own translation of the label. Add keys for your domain models so non-English panels don't leak English:

// lang/fr/undo-toast.php
return [
    'models' => [
        'Post' => 'article',
        'Comment' => 'commentaire',
    ],
];

Bulk actions and keyboard flow

Because mod+z now works while a checkbox, radio or button has focus, the bulk-delete flow works without clicking away: select rows, delete, then mod+z. Ensure your own JS doesn't intercept the shortcut or trap focus in a way that prevents the toast from receiving it.

Testing in your app

Assert the actual delete and undo outcomes rather than the toast text, since notification assertions may change when replacement is on. For Livewire tests: call the action, assert the row is gone, invoke undo, assert the row (and any restored relations) is back. Add an explicit case for the "no undo entry" path to confirm Filament's notification still fires.

Gotchas and Tips

  • Double "Deleted" toasts were the main pre-0.2.0 annoyance; upgrading fixes it. If you still see both, you likely customised successNotification()/successNotificationTitle() (which intentionally keeps Filament's notification) or overrode the action's notification behaviour yourself.
  • No undo entry means Filament's notification. If a delete is blocked from producing an undo, users get the ordinary success notification. Write a test for that branch; it is easy to forget a policy or condition that suppresses undo.
  • Hard-delete relation restore is insert-only. It does not reconcile deletions or update existing rows. If a related row already exists, it is left alone. Unique constraints or partially restored data can therefore make the restore fail — and because it runs in the same transaction, the whole undo fails. Log and surface these failures; the failed toast intentionally stays until dismissed.
  • Unsupported relation types (HasManyThrough, MorphToMany, custom relations) are not restored. Model the relation as one of the supported types or handle it after the undo yourself.
  • Pivot columns are restored for BelongsToMany, but verify timestamps/extra pivot data survive if your schema depends on them.
  • Keyboard shortcut scope. mod+z works with form controls focused, but should not fire while typing in text inputs (that would break native text undo). If you add your own global shortcut handlers, don't fight the package's.
  • replaceSuccessNotification closure mistakes. Return a strict boolean; a truthy non-boolean from a loosely written closure can make behaviour harder to reason about. Keep the closure cheap — it may run per action invocation.
  • Translation fallbacks. If a model label is missing, the English default is used. Add keys for every model you expose in non-English panels, and check plural forms if you customise strings — the package tests plural rendering (including Russian, Ukrainian, Polish and Czech forms), but your overrides are your responsibility.
  • Don't restyle the toast stack. The 0.2.0 design pass handles rounded progress lines, stack height/tint retention, fan-out on touch, gap hover behaviour, dark-mode shadow and Windows High Contrast. Custom CSS or clip-path animations can reintroduce the clipping and stack-collapse bugs.
  • Accessibility behaviour is intentional. Failed undos are announced as alerts and persist; successes stay long enough to read. Don't shorten or auto-dismiss failures.
  • Upgrade test pass. v0.2.0 changes notification replacement, adds relation restoring and translation keys, and tweaks keyboard handling. Re-run your Livewire/feature tests around delete actions and re-check French/Arabic copy if you assert on toast text.
  • Extension points are the model interface, the per-action relation map, the replacement closure and translation overrides. For anything else (custom toast markup, extra undo side effects), listen to your own model/action events rather than modifying vendor code.
  • Package hygiene improved (Security policy, Dependabot cooldown, pinned Actions, leaner dist), so upgrades should be low-risk — but pin your Composer constraint sensibly while you validate the notification and relation changes.
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.
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk