Quality check · lesson 22 of 23 · Error Prevention And Recovery

Fake undo

Underlying principle: Recovery begins before the error. Clear consequences, suitable constraints, preserved work, and a visible correction path reduce the cost of a mistake.

Treat undo as an implementation contract: capture state before commit, block or re-label undo after external side effects, and report restored, expired, failed, partial, and final states separately.

Start with the decision

Does this fit your task?

Use it when a toast undo, command undo, bulk undo, or keyboard undo may hide partial restoration, expired windows, external effects, or overwritten recovery state.

Review the boundary: Compare the task with the alternatives in the decision section.

Review the decision →
Study the interaction

Follow the task before choosing the component

Recovery begins before the error. Clear consequences, suitable constraints, preserved work, and a visible correction path reduce the cost of a mistake.

01 / Recognize the need

What the person is doing

A product shows Undo in a toast, snackbar, activity row, command bar, keyboard shortcut, history stack, or recovery panel after a completed action.

02 / Design the response

What the interface must communicate

Treat undo as an implementation contract: capture state before commit, block or re-label undo after external side effects, and report restored, expired, failed, partial, and final states separately.

Pre-action state with enough identity, relationship, order, permission, and context captured for reversal.

03 / Judge the outcome

What to look for

What exact state is captured before the action, and what proof shows it can be restored?

The undo label names the action or object when ambiguity is possible.

Decision first

Choose this pattern when the problem matches

Use when

  • Use it when a toast undo, command undo, bulk undo, or keyboard undo may hide partial restoration, expired windows, external effects, or overwritten recovery state.

Avoid when

  • Choose an alternative when the task calls for a different interaction.

Problem it prevents

A product shows Undo in a toast, snackbar, activity row, command bar, keyboard shortcut, history stack, or recovery panel after a completed action.

Test the behavior

Try strong and weak versions of the interaction

Open the working example, try its controls, and compare the behavior against the decision guidance.

In the lab you can
  • switch between strong UI, weak UI, strong UX, and weak UX;
  • trigger required, empty, loading, error, and recovery states;
  • inspect keyboard and accessibility expectations beside the demo.
Launch Fake undo in the lab
Pattern anatomy

What a strong implementation has to make clear

User need

A product shows Undo in a toast, snackbar, activity row, command bar, keyboard shortcut, history stack, or recovery panel after a completed action.

Pattern promise

Treat undo as an implementation contract: capture state before commit, block or re-label undo after external side effects, and report restored, expired, failed, partial, and final states separately.

Required state

Pre-action state with enough identity, relationship, order, permission, and context captured for reversal.

Failure to inspect

Undo restores a deleted item name but loses comments, permissions, folder path, tags, or sort position.

Access contract

Announce completed, undo available, restored, expired, failed, partial, and final states through status text.

Quality bar

The difference between expert and weak execution

Strong implementation

Specific, visible, recoverable

  • Deleting Quarterly report stores the row ID, folder, owner, sort position, labels, shared access, and selected filter, then Undo restores the row to the same list location.
  • A user archives a task by mistake, activates Undo, and the task returns with its original owner, due date, tags, position, and selection state.
  • A user sees Undo expired after the local recovery window ends and can still open Trash because the object moved to a durable recovery surface.
Weak implementation

Vague, hidden, hard to recover from

  • A bulk archive action offers one Undo button, but a second archive overwrites the first recovery target.
  • A user clicks Undo after deleting a shared file and the file name reappears, but collaborators, comments, and folder path are lost.
  • Undo restores a deleted item name but loses comments, permissions, folder path, tags, or sort position.
  • A second delete overwrites the first recovery payload, so Undo restores the wrong item.
UI guidance
  • Do not label an action Undo unless the system has captured enough state to restore the affected object, order, relationships, permissions, counts, focus context, and visible outcome.
  • If recovery is partial, delayed, external-effect-limited, permission-limited, or unavailable after a commit boundary, label the action honestly as Restore from trash, Request recovery, Recreate, Retry, or Contact support instead of Undo.
UX guidance
  • Users should trust that activating Undo returns them to the state before the action, not a best-effort approximation that hides what remains changed.
  • Treat undo as an implementation contract: capture state before commit, block or re-label undo after external side effects, and report restored, expired, failed, partial, and final states separately.
Implementation contract

What the implementation must handle

States

  • Pre-action state with enough identity, relationship, order, permission, and context captured for reversal.
  • Completed recoverable state that names the affected action and exact target.
  • Undo available state with a visible, keyboard-reachable recovery control.
  • Restored state showing the object, values, relationships, counts, selection, and focus context returned.

Interaction

  • The undo label names the action or object when ambiguity is possible.
  • Activating Undo restores enough state for the user to trust that the action was reversed.
  • If restoration is partial, the UI says partial restore, restore available, request recovery, or open trash instead of Undo.
  • Undo remains reachable long enough for pointer, keyboard, screen reader, and distracted users, or the action is routed to durable recovery.

Accessibility

  • Announce completed, undo available, restored, expired, failed, partial, and final states through status text.
  • Keep undo labels object-specific when several recent actions are possible.
  • If undo expires while focused, move focus predictably to a final status or durable recovery link.
  • If recovery is unavailable because of external side effects or permissions, explain that boundary in text.

Review

  • What exact state is captured before the action, and what proof shows it can be restored?
  • Can any external recipient, payment, webhook, permission change, or audit event still observe the action after Undo?
  • Does Undo restore identity, order, relationships, labels, permissions, counts, selection, and focus context?
  • What happens if the user performs another action before clicking Undo?
Evidence trail

Source-backed claims behind this guidance

Material Design: Snackbars

Google Material Design - checked

Material snackbar guidance supports the toast-action boundary where Undo must be a truthful recovery action.

GitLab Pajamas: Saving and feedback

GitLab Pajamas Design System - checked

GitLab saving and feedback guidance supports clear save, failed-save, undo, and leave-warning distinctions.

Full agent/debug reference

Problem Context

  • A product shows Undo in a toast, snackbar, activity row, command bar, keyboard shortcut, history stack, or recovery panel after a completed action.
  • The action may affect object identity, list order, filters, permissions, relationships, notifications, background jobs, external recipients, payments, webhooks, or audit state.
  • The product may capture only part of the prior state or let the recovery window expire while the control still looks available.
  • Users may perform multiple actions quickly, change filters, leave the route, reload, go offline, or lose permission before trying to undo.

Selection Rules

  • Flag this anti-pattern when an Undo control does not restore the exact object, value, order, relationship, permission, selection, and visible status it claims to reverse.
  • Flag it when undo appears after an external side effect such as email, payment, webhook, permission notification, customer message, or production command has already left the system boundary.
  • Flag it when several actions overwrite one recovery target without showing which action Undo will reverse.
  • Flag it when undo expires silently or remains visible after the recovery window is gone.
  • Use undo when the product captures prior state before the action and can restore it faithfully before irreversible side effects occur.
  • Use restore from trash when recovery happens later from a durable deleted-items location with retention and restore metadata.
  • Use destructive action confirmation when exact recovery is impossible and users need to decide before commitment.
  • Use toast notification for disposable feedback only; a toast may carry Undo only when the recovery action remains reachable long enough and works truthfully.
  • Use autosave recovery when the recovery target is unsaved or uncertain local work rather than a completed reversible command.
  • Use confirmation fatigue to audit overuse of confirmations, but do not replace a broken undo with another prompt unless pre-action review is the right safeguard.

Required States

  • Pre-action state with enough identity, relationship, order, permission, and context captured for reversal.
  • Completed recoverable state that names the affected action and exact target.
  • Undo available state with a visible, keyboard-reachable recovery control.
  • Restored state showing the object, values, relationships, counts, selection, and focus context returned.
  • Undo expired state that removes or disables the control and explains the final commitment.
  • Undo failed state that reports what was not restored and why.
  • Partial restore state that is not labelled as full undo.
  • External side-effect state where undo is unavailable or truthfully labelled as request, revoke, restore, or follow-up.
  • Multiple-action queue state that shows which action each undo reverses.
  • Bad fake undo state where the control appears but restoration is absent, partial, stale, overwritten, or misleading.

Interaction Contract

  • The system captures reversible state before applying the action, not after users request undo.
  • The undo label names the action or object when ambiguity is possible.
  • Activating Undo restores enough state for the user to trust that the action was reversed.
  • If restoration is partial, the UI says partial restore, restore available, request recovery, or open trash instead of Undo.
  • Undo remains reachable long enough for pointer, keyboard, screen reader, and distracted users, or the action is routed to durable recovery.
  • When the undo window expires, the UI removes or re-labels the control and reports final commitment.
  • External effects are called out honestly; undo must not imply recalled email, payment, webhook, or notification unless that recall is actually implemented.
  • Multiple recoverable actions are queued, grouped, or scoped so one Undo cannot accidentally refer to a different action.

Implementation Checklist

  • Define what exact prior state must be restored for each action: ID, parent, order, labels, ownership, permissions, relationships, counts, draft values, and focus target.
  • Capture the restore payload before mutating local, server, and external systems.
  • Make undo idempotent and scoped to a stable action ID so duplicate clicks or retries do not corrupt recovery.
  • Block or re-label undo for actions with irreversible external effects, or delay those effects until the recovery window closes.
  • Keep recovery controls visible, keyboard reachable, and stable while focused; do not auto-remove a focused Undo button.
  • Handle multiple actions with an undo stack, per-item undo, grouped undo, or explicit commit boundary.
  • Report restored, expired, failed, partial, final, and unavailable states in text, not only by removing the toast.
  • Test reload, route changes, filters, pagination, selection, offline, duplicate actions, permissions, external notifications, and screen reader status before claiming undo.

Common Generated-UI Mistakes

  • Showing Undo after an action that has already sent email, money, permissions, or webhooks outside the product.
  • Restoring only a visible row while losing comments, labels, sharing, order, or ownership.
  • Letting a second action overwrite the first action's undo payload.
  • Using a disappearing toast as the only recovery path for an important object.
  • Keeping Undo visible after the server has already committed a permanent delete.
  • Treating rollback failure as success because the item name reappeared.
  • Saying Undo when the real action is open trash, recreate from template, request admin restore, or retry save.

Critique Questions

  • What exact state is captured before the action, and what proof shows it can be restored?
  • Can any external recipient, payment, webhook, permission change, or audit event still observe the action after Undo?
  • Does Undo restore identity, order, relationships, labels, permissions, counts, selection, and focus context?
  • What happens if the user performs another action before clicking Undo?
  • When does the recovery window expire, and how does the UI show final commitment?
  • Is this actually trash restore, autosave recovery, retry, confirmation, or support recovery rather than undo?
Accessibility
  • Do not rely on a disappearing visual toast for important recovery; make the control reachable and stable for keyboard and assistive technology users.
  • Announce completed, undo available, restored, expired, failed, partial, and final states through status text.
  • Keep undo labels object-specific when several recent actions are possible.
  • If undo expires while focused, move focus predictably to a final status or durable recovery link.
  • Do not communicate restoration success only by visual row reappearance; state what was restored.
  • If recovery is unavailable because of external side effects or permissions, explain that boundary in text.
Keyboard Behavior
  • Undo controls must be reachable through Tab or a documented shortcut while the recovery window is valid.
  • A focused Undo control must not disappear without a replacement status or recovery path.
  • Keyboard undo shortcuts must operate on a visible, current undo stack or announce when no action can be undone.
  • After Undo, focus returns to the restored object, the recovery status, or the command source in a predictable location.
  • If multiple actions are queued, keyboard users can inspect which action each Undo command targets.
  • When undo is unavailable, disabled controls include a reason or are replaced by the correct recovery action.
Variants
  • Toast undo that does nothing
  • Partial restore labelled undo
  • External side-effect undo
  • Overwritten undo target
  • Expired undo still visible
  • Undo restores wrong item
  • Bulk undo ambiguity
  • Keyboard undo without stack
  • Optimistic undo failure
  • Undo after permanent commit

Verification

Source trail checked:

Saved items