Hold to confirm
FreeA destructive action that asks for intent, not a dialog. The fill soaks out from where you pressed, a countdown shows what is left, and releasing early drains it back.
Production pipeline
rk_live_••••4f2a · last used today
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/hold-to-confirm.json
Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
Use it for single, irreversible actions where a confirmation dialog would interrupt more than protect: revoking a key, ending a session.
onConfirm runs once, when the fill completes. The button then shows its done label and stays disabled.
Keyboard users hold Space or Enter; the description tells screen-reader users how it works.
import { HoldToConfirm } from "@/components/ui/hold-to-confirm" export function RevokeKey({ id, onRevoke }) { return ( <HoldToConfirm label="Hold to revoke key" doneLabel="Key revoked" onConfirm={() => onRevoke(id)} /> ) }
Examples #
Revoke a key
Try releasing before the fill completes. Nothing happens.
API reference #
All props except onConfirm are optional.
Accessibility #
A native button with a description explaining the hold. Pointer capture means sliding off the button still ends the hold cleanly.
Motion #
The fill grows from the press point at the hold's own pace and drains back on the settle curve if released. Under reduced motion the soak becomes four notches on the same clock, and the countdown is unchanged.