shadcn.io is not affiliated with official shadcn/ui
Delete Confirm Hold CRUD Block for Radix UI
A shop's bundle list with a trash button on each row and an alert that says what goes with the bundle, offers Archive instead, and deletes only after a 1.2 second hold, leaving Undo behind.
Installation
Overview
Make deleting a record take a decision, with this delete confirmation for React with Radix UI. It starts from the Bundles page of Bundlemere, a shop tool: five real rows, each with its name, how many listings it carries in how many shops, a status Badge and a trash Button, under a soft scrim inside a hairline frame with a plus mark on each corner. The trash opens an Alert Dialog that says what goes with the bundle in a Data List, counted from the record: "38 listings in 3 shops leave with it", "212 placed, history is kept". The safer ways come first: Cancel has focus, then "Archive instead", which keeps the bundle and marks it Archived. The destructive button is a Long Press Button: "Hold to delete" confirms only after a full 1.2 second hold, a short press says "Keep holding to delete." in the alert's polite line, and an outside click closes nothing. A deleted bundle's row becomes "Deleted Orchard bundle." with Undo and Dismiss in the same box, and the foot of the list says what happened beside an Undo. There is no Shine button here: the destructive action is the only commit. Dismissing every row shows an Empty state without the frame changing height. For catalogues, libraries and any list where deleting costs something.
FAQ
Why is the alert already open, and what do I keep?
So you can see it without a click. On load the alert is a copy drawn in place over the real bundle list: a native dialog element that isn't modal, so nothing is trapped, hidden or focused. A row's trash opens the real Alert Dialog, modal, with its focus trap, Escape and focus on Cancel, and the copy stays closed until a reload. Both show the same ConfirmBody component and share the block's state. In your app keep the Alert Dialog and drop the copy: the "in-place" state, the scrim and the dialog element in the frame.
How does the hold work, and what if I can't hold a pointer?
The button fills over 1.2 seconds while it is pressed and confirms when the fill is full; letting go early sends it back and the alert's polite line says "Keep holding to delete." Enter or Space held does the same, so the keyboard has a route, and the button is described as a hold to screen readers. Under reduced motion the fill fades instead of sweeping. If your users need a no-hold route, add a second destructive button behind a typed confirmation, as dialog-confirm-delete does.
What does Archive instead do?
It keeps the record and changes its status to Archived, closes the alert and puts focus back on the row's trash. The foot says "Archived Orchard bundle in this demo." with an Undo that restores the list exactly as it was. In your app that is the call that hides the bundle from shops without removing its listings or orders.
What do Undo and Dismiss restore?
Undo restores the last change only, a delete or an archive: the list is stored as it was and set back, and focus lands on the restored row. A new change replaces it, and nothing times out. Dismiss drops a deleted row's placeholder for good, without a way back, and moves focus to the row that took its place.
What stays local, and how do I wire a real delete?
The five bundles are typed in BUNDLES and live in this tab; a reload brings them back, and nothing is sent. In your app call your API from hold and archive, show a server refusal in the alert's polite line, and make Undo call a restore endpoint. Leave the confirmation on the server side too: the hold is a guard for people, not for requests.
Is it accessible from the keyboard?
Yes. The real alert is named by its title and described by its sentence, focus starts on Cancel and stays inside until it closes, and focus returns to the row's trash on every way out. Each trash button is named for its bundle. The copy shown on load moves no focus; Escape inside it behaves like the real alert's.