DEV Community

DCT Technology Pvt. Ltd.
DCT Technology Pvt. Ltd.

Posted on

Behind the Scenes of a Reliable ‘Undo’ Button

Ever clicked Undo and felt that small sigh of relief?
Now imagine being the one responsible for making sure it always works — even when things get chaotic behind the scenes.

It sounds simple, but building a truly reliable Undo feature is one of the trickiest things in web development. Let’s dive into the unexpected challenges and how to actually architect one like a pro.

💥 Why Undo Isn’t Just "Reversing" an Action

Many developers assume Undo is just about reversing what the user did.

“User deleted a post? Just restore it.”
“User moved a task? Just move it back.”

But what if:

  • The user undoes multiple actions in sequence?
  • The system state changes between actions (e.g. real-time collaboration)?
  • There are server-side mutations or side effects (like sending emails)?

The deeper you go, the messier it gets.


🧱 There Are Two Core Approaches to Undo

To implement a proper undo system, you generally choose between:

1. Command Pattern (aka Action Stack)

You save every user action as a command object with do() and undo() methods.

class MoveCard {
  constructor(card, fromList, toList) {
    this.card = card;
    this.from = fromList;
    this.to = toList;
  }

  do() {
    this.to.addCard(this.card);
    this.from.removeCard(this.card);
  }

  undo() {
    this.from.addCard(this.card);
    this.to.removeCard(this.card);
  }
}
Enter fullscreen mode Exit fullscreen mode

You maintain a stack of such commands. When the user hits Undo, you just call undo() on the latest.

📚 Resource: Command Pattern Explained in JS

2. State Snapshots (Time Travel Debugging Style)

Instead of reversing actions, just store app state snapshots before every change.

Then, Undo = go back to previous state.

Pros:

  • Great for simple apps or prototypes
  • Easy to implement with Redux or Zustand

Cons:

  • Memory intensive
  • Not ideal for real-time or collaborative apps

🧠 Real World Complications Nobody Talks About

Building Undo isn’t just about code — it’s about UX and user expectations too.

Here are the common pitfalls that devs often overlook:

  • Cross-device syncing: What if a user hits Undo on mobile but performed the action on desktop?
  • Server-side operations: Can you reverse DB writes? What about emails sent?
  • Chained effects: Undo one thing, but it affects 3 other things?
  • Expired actions: Should users be able to undo after 10 seconds? After a page reload?

👉 If you don’t plan for these, you’re not building a reliable Undo.


✅ Pro Tips to Design a Better Undo Experience

Here’s what we’ve learned from building Undo in production apps:

  • Use optimistic UI, but delay the actual server call until after the Undo window (like Gmail’s "Undo Send")
  • Track every action with unique IDs, timestamps, and metadata
  • Limit Undo history to reduce memory and bugs
  • Make the UX predictable — users should always know what will be undone

🧪 Bonus: React Hook for Basic Undo/Redo

Want to experiment in your own React app? Try this basic undo stack:

import { useState } from 'react';

function useUndo(initialState) {
  const [past, setPast] = useState([]);
  const [present, setPresent] = useState(initialState);
  const [future, setFuture] = useState([]);

  const set = (newPresent) => {
    setPast([...past, present]);
    setPresent(newPresent);
    setFuture([]);
  };

  const undo = () => {
    if (!past.length) return;
    const previous = past[past.length - 1];
    const newPast = past.slice(0, -1);
    setPast(newPast);
    setFuture([present, ...future]);
    setPresent(previous);
  };

  const redo = () => {
    if (!future.length) return;
    const next = future[0];
    const newFuture = future.slice(1);
    setPast([...past, present]);
    setPresent(next);
    setFuture(newFuture);
  };

  return [present, set, undo, redo];
}
Enter fullscreen mode Exit fullscreen mode

Use this for counters, to-do apps, or small experiments.
Not for production-scale apps — but a great playground!


🤝 Let’s Talk!

Have you ever tried implementing Undo?
Did it turn into a rabbit hole of chaos like it did for most of us?

Share your experience or drop questions below — I’d love to chat more.


👉 Follow [DCT Technology] for more deep dives into development, design, system architecture, and IT consulting.

Let’s keep learning — and undoing — the right way. 😉


#webdevelopment #reactjs #uxdesign #javascript #programming #devtools #systemdesign #frontend #developers #softwareengineering #dcttechnology #undo #codingtips #opensource #techstories #uiux

Top comments (0)