Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Undo Toast Notification Block for React

An invoicing app's list with a delete on every row: the toast says how many are deleted with an Undo, a second delete merges into the same toast and starts its wait again, and Restore deleted on the page does the same as Undo.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Let people take a delete back, with this undo toast for React with Base UI. It's the invoices page of Inkledger, an invoicing app, in a hairline frame with a plus mark on each corner: a top bar, a list of four invoices with the customer, the number, the amount and a Delete button each, and a Restore deleted Button that is always on the page. Deleting an invoice raises a toast, "1 invoice deleted", naming who it was and wearing the look of the catalog's Toast, with an Undo. Delete a second one while it is up and the same toast becomes "2 invoices deleted" and starts its wait again instead of piling up; Undo brings every deleted invoice back in its place, and an emptied list shows a designed Empty state. The toast times out, so its action is also on the page: Restore deleted does the same as Undo, for as long as you like. On load one invoice is already deleted and its toast is drawn in place; the first Delete raises a real one through the block's own toaster, at the end of the screen. It's built from Toast, Button, Empty and Guides, with CSS motion only. For lists, mail, files and any delete you would rather not confirm first.

FAQ

Why is a toast already on the page, and what do I keep?

So you can see an undo toast without deleting anything: on load the Tavish Print invoice is already deleted and its toast is drawn in place at the stage's foot end, using the catalog toast's own classes, and its Undo works. The first Delete raises a real toast and the drawn one stays gone until a reload. In your app keep the toaster and the raise call, and drop the drawn copy: the "in-place" state, DrawnToast and the ol in the frame.

How do two deletes become one toast?

Every deletion raises the same toast id with toaster.add({ id: "deleted", type: "success", title, description, actionProps: { children: "Undo", onClick }, timeout }); adding with an id that is up updates that toast in place and refreshes its timer.The title and the names come from one function of the deleted list, so the toast always says what the list says, and the block builds the whole message again at each delete.

How long does the toast wait, and what if I miss it?

Six seconds after the last delete (STAY), paused while the pointer or keyboard focus is on it. If it goes, nothing is lost: Restore deleted at the top of the page brings back every deleted invoice, exactly as Undo does, so the action never exists only in a toast that disappears. In your app the server decides how long a delete can be undone; the page's control should live as long as that.

What does Undo do?

It puts every deleted invoice back at its own place in the list, takes the toast away and says how many came back in a polite status message, and moves focus to the first restored invoice's Delete button. A toaster can deliver an action twice, and the second delivery finds nothing to bring back, so it does nothing. In your app call your restore endpoint in restore and keep the rows until it answers.

Where does focus go after a delete?

To the next invoice's Delete button, or to Restore deleted when the list has run out, so a keyboard user can delete down the list without losing their place. The real toast never takes focus.

Is it accessible?

The real toast lives in a live region that speaks it once. Undo and Dismiss name the toast they belong to, every Delete names its invoice and customer, the list is named "Invoices" and its count is written out ("3 of 4"). Restore deleted is quiet while nothing is deleted and answers a press in words rather than disappearing. The drawn copy is a list named "Notifications".

What stays local?

Everything: the four invoices are typed at the top of the file, a delete only hides a row and Undo shows it again, and a reload resets the page. Nothing is deleted anywhere.

How does it look on a phone?

The rows keep their customer, amount and Delete, with long names truncated, the stage is a little taller, and the drawn toast takes the width of the page minus a margin at its foot. The real toast is the library's own: full width at the end of the screen.

  • Pro

    A messaging app's thread with a message toast that carries a Reply action: it never times out, Reply takes it away and puts the sender in the composer with focus, and Receive a message raises the next of three, up to three at once.

  • Pro

    The settings page of a form builder with its Save settings button: two success toasts are drawn on the page, and pressing Save raises a real toast through the block's own toaster, stacking up to three.

  • Pro

    A saved-settings toast pill for a settings panel: a success check, a message, an Undo button wearing a ring that drains over six seconds, and a dismiss button.

  • Pro

    A summary band with a rolling unread count and a mark all read that fades the dots in turn and offers an exact undo, over a list where every row can be marked unread again.

  • Pro

    An archive of notifications as a table whose auto-delete column is worked out again when you pick a retention period, with a restore per row, an undo, and an alert dialog before it empties.

  • Pro

    A post scheduler's publishing queue with an Add a toast button: the toasts overlap in a stack of three, open into a list on hover or focus, and the rest wait their turn.