shadcn.io is not affiliated with official shadcn/ui
Two Actions Dialog Block for React
A mail client with its sent confirmation shown open: a dialog with a View message button and an Undo whose label counts down from 10 while a fill drains, with Return to drafts staying on the page.
Installation
Overview
Give a person a moment to take a send back, with this two-button confirmation for React with Base UI. It opens from a new message in Heronmail, an email client: the header holds an outline Send Button, and the mail list is drawn under a soft scrim inside a hairline frame with a plus mark on each corner, the message first as a Draft. The Dialog says "Message sent" with who it went to, and its footer holds a pair: Undo, outline, whose label counts down from 10 while a fill drains behind it, and View message, the one Shine Button, which has focus. At zero Undo reads "Undo expired" and stays focusable. The Undo is a shortcut, never the only way back: the header's button turns into Return to drafts as soon as the message is sent and works whenever the person gets to it, so nobody is punished for being slow. The pair stacks on a phone and sits side by side from the small breakpoint up. For preview the dialog is drawn open in place when the page loads, its clock stopped at Undo (10); Send opens the real Dialog, where the clock runs from the moment it opens. For email, chat, scheduled posts and any action that can be taken back.
FAQ
Why is the dialog already open, and why is the clock stopped?
So you can see it without a click, and so a poster or a gallery card never ages. On load the dialog is a copy drawn in place over the mail list: a native dialog element that isn't modal, so nothing is trapped, hidden or focused. In it Undo stands still at "Undo (10)" with its fill full, and a muted line says the clock runs when the dialog is opened from Send. Send in the header opens the real Dialog, modal, with its focus trap and Escape, and there the clock runs. Both wrappers share SentFields and the block's state. In your app keep the Dialog and drop the copy.
How does the countdown work?
The catalog Timer, kept out of sight, counts down from ten seconds and sets the number in the label; the fill is a plain CSS transition of the same length, so it never needs a frame loop and is hidden under reduced motion, where the digits still run. The block speaks twice: once when the clock starts ("Undo is available for 10 seconds") and once at zero. It never reads out every second. Closing the dialog stops the clock and opening it starts a new one.
Does a timed Undo fail people who need longer?
It would if it were the only way. That is why it isn't: the moment the message is sent, the header's Send turns into Return to drafts, which does the same thing with no clock, and the expired Undo says so in a line under the message. The window is a convenience for the quick case, not a limit on a person's ability to change their mind. In your app keep an equivalent always on the page, such as an Unsend or a Move to drafts action on the message, for as long as your server can honour it.
What do the buttons do here, and how do I wire them up?
Nothing is sent. Closing the dialog, with View message, Close or Escape, leaves the drawn message as Sent; View message also tints the row as opened. Undo, while it lasts, takes the message back to Draft and says so. In your app hold the message server-side for the length of the window or send a recall, and make undo call it; if the server can no longer honour it, say so inside the dialog instead of pretending.
Where does focus go, and how does it close?
The real dialog opens with focus on View message, the one primary, not on Undo, so a stray Enter doesn't take the message back. Escape and Close keep it sent. After any result the header's button has changed (Send to Return to drafts and back), so about 300 ms later focus moves to the button that took its place. View message is the focus target through initialFocus.
Related
- Pro
Success Dialog
Status and errorsAn invoice page with its payment confirmation shown open: a dialog with a drawn check, a receipt list with a copy button for the reference, and one button that settles the invoice.
- Pro
Unsaved Changes Dialog
Confirm and consentAn essay editor with its leave prompt shown open: an alert dialog that lists what changed since the last save and offers Save and leave, Discard changes and Keep editing.
- Pro
Session Timeout Dialog
Status and errorsA bank's accounts page with an alert dialog shown open that warns before an idle session ends: a one-minute clock with a draining bar, Stay signed in and Sign out now, and a signed-out view at zero.
- Pro
Rate Limit Dialog
Status and errorsAn API console with its 429 notice shown open: a dialog with the quota used, the plan's limit, a clock to the reset and a Countdown Button that turns into Retry request when the wait ends.
- Pro
Confirm Action Dialog
Confirm and consentA newsletter editor with its publish confirmation shown open: an alert dialog that lists what happens to the issue, a box that remembers the answer, and a foot that gives the question back.
- Pro
Save Draft Dialog
Notes and editingA publishing editor with its save-draft dialog shown open: a name, a folder, an autosave choice with a sentence that follows it, and a discard that asks again in the same row.