shadcn.io is not affiliated with official shadcn/ui
Undo Toast Notification Block for Svelte
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.
Installation
Overview
Let people take a delete back, with this undo toast for Svelte with Ark 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?
toaster.create({ id: "deleted", type: "success", title, description, action: { label: "Undo", onClick }, duration }); calling create with an id that is up updates that toast in place instead of adding another.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".