shadcn.io is not affiliated with official shadcn/ui
Success Dialog Block for Radix UI
An 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.
Installation
Overview
Confirm a payment the way a receipt would, with this success dialog for React with Radix UI. It opens from an invoice in Cobblepay, an invoicing app for freelancers: the header holds an outline Pay invoice Button, and the invoice itself is drawn under a soft scrim inside a hairline frame with a plus mark on each corner, its status pill reading Due. The Dialog shows a drawn check, a ring and a tick whose strokes draw once and stay still under reduced motion, in foreground weight rather than a green surface, then "Payment sent", one sentence that says no money moved in this demo, and a Data List of the amount, who it went to and the reference with its own Copy Button. Back to invoices, the one Shine Button, closes it, the pill turns to Paid and the header's button becomes View receipt, which opens the same dialog again. For preview the dialog is drawn open in place when the page loads; Pay invoice opens the real Dialog. For checkouts, invoices, bookings and any step that ends in a receipt.
FAQ
Why is the dialog already open, and what do I keep?
So you can see it without a click. On load the dialog is a copy drawn in place over the invoice: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. Pay invoice in the header opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same ReceiptFields component. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.
How is the check drawn, and what happens under reduced motion?
It is one inline image with a ring and a tick, each a path with a pathLength of 100. A CSS transition from a dash of 0 to 100 (starting: styles, no library) draws the ring first and the tick half a second later, once, when the dialog appears. Under reduced motion the transition is off and both strokes are whole at once. The image is hidden from assistive technology, since the title already says what happened.
What does the copy button do?
It copies the reference to the clipboard and says so politely, through the status line inside the dialog, since a modal hides the page's own. If the clipboard refuses, the button shows a cross and says it couldn't copy. The reference, the amount and the payee are typed constants; in your app take them from the payment the server confirmed.
What does Back to invoices do here, and how do I wire it up?
Closing the dialog, by that button, Close or Escape, settles the drawn invoice: its pill turns from Due to Paid and a polite status message says the invoice was marked paid in this demo and nothing was charged. In your app show this dialog only after the payment provider has confirmed, and change the invoice from the provider's result, not from closing the dialog. Never call it from a click that only started a payment.