Skip to content

Undo Commit Toast

An undo window that defers the action instead of reversing it, and pauses when you tab toward the button.

DOM + CSS0 deps1 file · 8 KB TSX

Prominimaleditorial
Preview

Props

6000
Pause on hover

The source is part of Pro

$27/month or $179 once. See Pro

No runtime dependencies
"use client";

import { useEffect, useRef, useState } from "react";

type Pending<T> = {
  id: number;
  item: T;
  index: number;
  /** Absolute time the commit is due. Null while paused. */
  deadline: number | null;
  remaining: number;
};

export function UndoCommitToast<T extends { id: string; label: string }>({
  items: initial,
  undoWindow = 6000,
  pauseOnHover = true,
  onCommit,

  // ---------------------------------------------------------------
  // Full source available with a viberdy Pro subscription.
  // https://viberdy.dev/pricing
  // ---------------------------------------------------------------
}
Details

About this pattern

Undo is usually built backwards: the destructive thing happens straight away and the undo button tries to put it back. That works for a local array and falls apart for anything real, because reversal cannot restore a server-generated id, a created timestamp or a position in an ordered list, cannot re-establish relations that were cascaded away, and cannot unsend whatever the action triggered. The correct shape is to DEFER — hide the row immediately so the interface still feels instant, and hold the actual work until the window expires. Nothing needs undoing because nothing has happened. Three details make the window itself behave. The countdown is an absolute deadline paired with a remaining duration rather than a single timeout, because a timeout cannot be paused and resumed at the exact point it stopped. The ring is animated by writing its dash offset straight to the element, since a state update per frame re-renders the whole list sitting behind the toast. And the timer pauses on FOCUS as well as hover, which is the detail almost everyone misses and is a plain accessibility failure when it is missing: a keyboard user tabbing toward the button cannot reach it inside a six-second window. Pending commits are also flushed on unmount, or someone removes a row, navigates away, and watches it silently return.

Curator’s note

Pause the countdown on focus, not only on hover. A keyboard user cannot reach the Undo button inside six seconds otherwise.

Pairs well with

Pro
Pro
Pro