WebberUI

Undo Snackbar

An undo prompt bar with a countdown progress ring that confirms the action automatically when time runs out.

A snackbar that pops up from the bottom after a destructive action, holding a message, an undo button, and an SVG ring countdown (five seconds by default): pressing undo cancels the action and reports through onUndo, while the countdown reaching zero fires onCommit to make the action take effect for real. The countdown pauses automatically on pointer hover or keyboard focus. You can wire it up directly with controlled props, or use useUndoSnackbar for ready-made state management.

Loading preview…
npx shadcn@latest add https://webberui.com/r/undo-snackbar.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

5000
<UndoSnackbar />

Installation

npx shadcn@latest add https://webberui.com/r/undo-snackbar.json

Or, once registries are configured in components.json, install it as @webberui/undo-snackbar.

Usage

import { UndoSnackbar, useUndoSnackbar } from "@/components/ui/undo-snackbar";

function Inbox() {
  const { show, snackbarProps } = useUndoSnackbar({ duration: 5000 });

  const handleDelete = (item: Item) => {
    hideItem(item.id); // optimistically remove it from the screen first
    show(`Deleted "${item.title}"`, {
      onUndo: () => restoreItem(item.id), // undo pressed within five seconds → restore
      onCommit: () => permanentlyDelete(item.id), // timed out → delete for real
    });
  };

  return (
    <>
      {/* ...list... */}
      <UndoSnackbar {...snackbarProps} />
    </>
  );
}

You can also skip the hook and manage the open state yourself with controlled props, closing it inside onUndo / onCommit.

Props

UndoSnackbar

PropTypeDefaultDescription
openbooleanWhether the snackbar is shown (controlled); close it inside onUndo / onCommit
messagestringThe snackbar message text
durationnumber5000Total countdown duration (milliseconds); reaching zero fires onCommit
undoLabelstring"復原"Text of the undo button — the built-in default is the Traditional Chinese for "Undo", so pass this prop to localize it
onUndo() => voidCalled when undo is pressed: cancels the action and closes
onCommit() => voidCalled when the countdown ends: the action takes effect for real
resetKeynumber | stringWhen showing the same message repeatedly, changing this value restarts the countdown
positioning"fixed" | "absolute""fixed"Snaps to the bottom of the window or of the nearest positioned ancestor
classNamestringForwarded to the snackbar panel

useUndoSnackbar

ItemTypeDescription
options.durationnumberTotal countdown duration (milliseconds), default 5000
options.undoLabelstringText of the undo button
show(message, handlers?)functionShows the snackbar and registers onUndo / onCommit; any pending action still outstanding is committed immediately first
close()functionCloses silently, firing no callback
snackbarPropsUndoSnackbarPropsSpread straight into <UndoSnackbar {...snackbarProps} />

Accessibility

  • The snackbar uses role="status" and aria-live="polite", so the message is announced automatically by the screen reader when it appears
  • The countdown pauses on pointer hover or keyboard focus (tabbing to the undo button) and only resumes once you leave, guaranteeing enough time to react
  • Undo is a native <button> with full keyboard support and a focus-visible focus ring
  • The ring countdown and the remaining seconds are visual aids and are hidden from assistive technology (aria-hidden)
  • When the user has "reduce motion" enabled at the system level, the enter and exit become a plain fade in / fade out with no offset or spring animation

On this page