Optimistic rollback

When the server rejects the change you already showed as done, the UI puts the old state back and tells you why.

put it back if the save failsundo it when the server says norevert the UI when the request failsrollback optimistic updateoptimistic update failed handlingun-like it when it doesn't workthe UI snapped backoptimisitc rollback

See it

Live demo coming soon

What it is

The unhappy-path half of optimistic UI. You showed the result before the server agreed; rollback is what you owe the user when the server disagrees. The shape is always the same three beats: record exactly what you are about to change, apply the guess, and on error undo that one change and say what happened.

Every data library has this baked in. TanStack Query does it with 'onMutate' (cancel in-flight queries, snapshot with 'getQueryData', write the guess with 'setQueryData'), 'onError' (restore the snapshot from context), and 'onSettled' (refetch server truth). SWR has 'optimisticData' plus 'rollbackOnError'. Redux Toolkit Query hands you 'patchResult.undo()'. Use it for cheap, frequent, almost-always-succeeds actions: likes, toggles, checkboxes, drag reorder. Never for anything irreversible or financial.

Gotcha: a silent revert reads as a haunted app. The toggle flips back on its own and the user either does not notice (and believes their change stuck) or notices and trusts nothing after that. Always pair the revert with a message and a retry. Second trap: concurrent mutations. Blindly restoring a whole old snapshot can wipe out a later mutation that succeeded, so undo only the failed mutation's own patch, keep conflicting mutations on the same record serialized or tagged by mutation ID, and reconcile against the server once things settle.

Ask AI for it

Make this mutation optimistic with a proper rollback. Before firing the request, cancel any in-flight refetches for the affected query, then apply a targeted patch and keep its inverse (or the previous values of only the fields this mutation touches) so the UI updates with zero delay. On error, undo just that mutation's patch rather than overwriting the whole cached snapshot, so a later mutation that already succeeded does not get erased. Tag mutations with an ID and serialize the ones that touch the same record instead of letting them interleave. On settle, invalidate the query and reconcile with server truth. Show a toast naming what failed with a 'Retry' action, and animate the revert (roughly 200ms) instead of snapping, so the user can see the state change back.

You might have meant

optimistic uiundoable actionerror recoveryvisibility of system statuschange blindness

Go deeper