Undo toast
A Sonner toast with an Undo action that either restores or commits the change.
npx shadcn@latest add https://ui.goodtabs.co/r/undo-toast.json
With the @goodtabs namespace in components.json: npx shadcn@latest add @goodtabs/undo-toast
- Motion references
- Type specimens
- Icon sets
The row goes away at once. Undo puts it back in the same place.
Commit on close
Draft is live
onCommit runs once the toast closes without an undo.
Usage
import { undoToast } from "@/components/ui/undo-toast"
undoToast("Removed Motion references", {
onUndo: () => restore(item),
onCommit: () => api.delete(item.id),
})Props
| Prop | Type | Default | Description |
|---|---|---|---|
| message | string | First argument. The toast title. | |
| onUndo | () => void | Runs when Undo is pressed. | |
| onCommit | () => void | Runs once if the toast closes any other way. | |
| description | string | Optional muted line. | |
| duration | number | 6000 | Milliseconds before it closes. |
Source
undo-toast/undo-toast.tsx
"use client";
import { toast } from "sonner";
type UndoToastOptions = {
/** Muted line under the message. */
description?: string;
/** Runs when the person presses Undo. Restore the item here. */
onUndo: () => void;
/** Runs once if the toast closes without an undo. Make the change permanent here. */
onCommit?: () => void;
/** Milliseconds before the toast closes on its own. */
duration?: number;
};
/**
* Shows a toast with an Undo action. Exactly one of onUndo or onCommit runs.
* Mount the Toaster from the toaster item once, then call this anywhere.
*/
function undoToast(message: string, { description, onUndo, onCommit, duration = 6000 }: UndoToastOptions) {
let undone = false;
const commit = () => {
if (!undone) onCommit?.();
};
return toast(message, {
description,
duration,
action: {
label: "Undo",
onClick: () => {
undone = true;
onUndo();
},
},
onDismiss: commit,
onAutoClose: commit,
});
}
export { undoToast };
For AI agents
Hand your agent this page, the markdown at /components/undo-toast/prompt.md, or the Copy AI prompt button above.
When to use
- Reversible actions like removing, archiving or unpublishing
- Instead of a confirm dialog, which interrupts the flow
When not to use
- Actions that cannot be reversed: ask first with an alert dialog
- Plain confirmations: use toast.success from the toaster
Agent notes
- Apply the change optimistically, then call undoToast; do the real delete in onCommit
- Needs the Toaster from the toaster item mounted once in the layout
- Exactly one of onUndo or onCommit runs. A dismissed toast counts as a commit
- Sonner makes the Undo button keyboard reachable and announces the toast