Hold to Confirm Button
A free hold to confirm button React component with cancellable progress, keyboard parity and two visual directions.
Contractor payouts
Release the July payout run
US$18,206.40 goes out to 143 contractors the moment the run clears. A released run cannot be recalled.
Approved by A. Osei and R. Vance. Settles in one business day.
Customise
Code
<BtnHoldConfirm />Hold to Confirm Button is a free button component for Next.js and React, styled with Tailwind and animated with Motion. It makes deliberate actions safer by requiring a continuous press for a bounded duration, then calls onConfirm once and shows a clear success state before resetting.
Pointer capture keeps a mouse, pen or touch attempt deterministic even when it moves away from the control. Space and Enter provide the same hold and cancellation behaviour for keyboard users, while early release, pointer cancellation, lost capture, blur or Escape always restores the resting state. Reduced motion preserves the full hold requirement with fixed geometry, a static brand surface and textual feedback instead of continuous travel.
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/btn-hold-confirmUsage
import { BtnHoldConfirm } from "@/components/btn-hold-confirm";
export default function PublishControl() {
return (
<BtnHoldConfirm
label="Hold to publish"
holdingLabel="Keep holding"
successLabel="Published"
onConfirm={() => {
console.log("Publish confirmed");
}}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | "Hold to confirm" | Resting accessible and visible label. |
| holdingLabel | string | "Keep holding" | Visible label while an attempt is active. |
| successLabel | string | "Confirmed" | Visible completion label and polite announcement. |
| holdDuration | number | 1200 | Completion duration in milliseconds, clamped to 600-3000. |
| width | number | 184 | Button width in CSS pixels, clamped to 144-280. |
| height | number | 48 | Button height in CSS pixels, clamped to 40-64. |
| progressDirection | "left-to-right" | "radial" | "left-to-right" | Visual progress treatment only. |
| disabled | boolean | false | Uses native button disabled behaviour. |
| onConfirm | () => void | undefined | Called exactly once after a completed hold. |
| className | string | undefined | Additional classes merged onto the button. |
Customisation
Hold to Confirm Button exposes two Tier 3 CSS variables. The fill token colours the resting and holding surface, and the success token colours the completed surface; progress is drawn as a theme-derived wash over the fill, so it needs no token of its own. Geometry and timing remain available through props:
<div
style={{
"--hold-confirm-fill": "var(--ring)",
"--hold-confirm-success": "var(--primary)",
}}
>
<BtnHoldConfirm
holdDuration={1600}
width={216}
height={52}
progressDirection="radial"
/>
</div>Frequently asked questions
- Is Hold to Confirm Button free for commercial use?
- Yes. Hold to Confirm Button is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Is the hold interaction accessible and performant?
- Yes. It is one native button with a stable accessible name, native disabled semantics, a visible focus ring and a polite live region for cancellation and completion. Pointer and keyboard users receive the same bounded interaction. The animated progress uses transform scaling or SVG pathLength rather than layout properties, and reduced motion keeps the hold timing while replacing travel with static textual feedback.
- How can I customise the hold duration and progress style?
- Set holdDuration between 600 and 3000 milliseconds, choose left-to-right or radial with progressDirection, and adjust width and height within their documented bounds. Use the two hold-confirm CSS variables to retheme the brand fill and the success surface without changing the component source.