Every product asks users to do irreversible things: delete a project, archive a conversation, remove a teammate. The default way to make those safe is a confirmation dialog, “Are you sure?”, and it’s one of the worst patterns in software. It interrupts the 99% of the time the user meant it, and it doesn’t even work: people click through confirmations on autopilot and delete the thing anyway.
Undo is the better answer. Instead of asking “are you sure?” before, let the action happen instantly and offer a way back for a few seconds after. It’s more forgiving, less annoying, and it makes your whole product feel safer to use. Here’s how to add it.
The pattern that replaces “Are you sure?”
The core move for deletes is deferred execution with an undo window:
- User clicks delete. The item disappears from the UI immediately, it feels instant and final.
- A toast appears: “Project deleted. Undo.” with a 5-10 second timer.
- Behind the scenes, you haven’t actually deleted anything yet. You’ve scheduled the delete to commit when the timer expires.
- If the user clicks Undo, you cancel the scheduled delete and the item reappears. If the timer runs out, the delete commits for real.
This gives users the confidence of instant action and the safety net of reversal, without a single interrupting dialog. Gmail’s “Undo Send” is the famous example; the same mechanic works for nearly any destructive action.
A prompt to build it:
Implement an undo pattern for [deleting a project]. On delete: remove it from the UI optimistically and show an undo toast with a countdown. Defer the actual server delete until the window expires; if the user clicks undo, cancel it and restore the UI. Handle the case where the user navigates away before the window closes. Show me how you manage the pending-delete state and the deferral before the UI.
Undo needs somewhere to undo to
For undo to be possible, the data has to survive long enough to restore. Two common approaches, often combined:
- Soft deletes. Instead of removing the row, set a
deleted_attimestamp. “Deleted” items are hidden but recoverable, and undo is just clearing the timestamp. A background job purges rows past a retention window. This also gives you a trash/recycle-bin feature almost for free. - A pending-operation buffer. For the short undo window specifically, hold the operation in memory or a short-lived record and only apply it when the window closes.
Soft deletes are the more robust foundation, they make undo trivial and also protect against the “oops, I need that back an hour later” case that a 10-second toast can’t.
Beyond delete: multi-step undo
For editing-heavy tools (editors, canvases, form builders), users expect ⌘Z to walk back through many actions, not just the last delete. That’s an undo stack: each user action pushes an inverse operation onto a stack; undo pops and applies it; redo maintains a parallel stack.
The key design decision is representing each action as a reversible command, “insert X at position Y” pairs with “delete range Y..Y+len.” Model actions as command objects with do and undo from the start; retrofitting reversibility onto a mutation-based codebase later is painful. You don’t need this for a simple app with a few destructive buttons, but if editing is core to your product, plan for it early.
Ship it and watch trust go up
Undo is almost purely additive, it removes a dialog and adds a safety net, so it’s low-risk to introduce. But it does change real behavior: deletes now defer, soft-deleted rows accumulate, and the pending-operation logic has edge cases (what happens if the user deletes, then immediately does something else to the same item?).
Roll it out the calm way:
- Ship it behind a flag. Your team uses it first, deleting and undoing aggressively to surface race conditions, especially the “navigate away mid-window” and “act on a pending-deleted item” cases.
- Enable for a cohort and watch two signals: how often users actually click Undo (if it’s frequent, you just prevented a lot of support tickets and data loss) and whether soft-deleted data is being purged on schedule.
- Ramp to everyone. The metric to celebrate is a drop in “please restore my deleted X” support requests, undo moves that recovery from your support queue to a button the user presses themselves.
If the deferral logic misbehaves, a delete that doesn’t commit, or an undo that restores stale state, the flag lets you fall back to the previous behavior instantly while you fix it, rather than leaving users with deletes they can’t trust.
Undo is one of those features that quietly raises the perceived quality of an entire product. Replace your confirmation dialogs with it, build on soft deletes so recovery is always possible, and let users move fast knowing they can always step back.
ShipSilently lets you introduce a behavior change like deferred deletes to one cohort at a time, and fall back instantly if an edge case surfaces. Try it free.