WebberUI

Hold to Confirm

A press-and-hold fill confirmation button: holding fills the progress from left to right with a slight tremor near completion, and only a full fill triggers it — preventing accidental taps on dangerous actions.

Loading preview…
npx shadcn@latest add https://webberui.com/r/hold-to-confirm.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

1.2
<HoldToConfirm />

Installation

npx shadcn@latest add https://webberui.com/r/hold-to-confirm.json

Installing also writes the --wb-duration-fast CSS variable into your global stylesheet.

Usage

import { HoldToConfirm } from "@/components/ui/hold-to-confirm";

<HoldToConfirm
  onConfirm={() => deleteAccount()}
  confirmedChildren="Deleted"
>
  Hold to delete account
</HoldToConfirm>

Props

PropTypeDefaultDescription
holdDurationnumber1.2How long (seconds) it must be held to confirm; the fill completes at a constant rate over this duration
onConfirm() => voidFires when the fill completes, exactly once per success
confirmedChildrenReactNodeContent shown after a successful confirmation; falls back to children when not provided
variant'danger' | 'default''danger'danger is the red scheme (for dangerous actions), default is neutral
classNamestringOverrides the default styles
childrenReactNodeButton content

All other <button> attributes (disabled, aria-*, and so on) are forwarded directly. A click never confirms — holding is the only confirmation gesture.

How it works

  • Constant-rate fill: on pointer down (or holding the space bar) the fill layer sweeps from left to right with scaleX at a linear rate; if you let go early it stops midway, and pressing again resumes from the current progress at the same rate
  • Tremor near the threshold: past 65% the button starts shaking slightly from side to side, with the amplitude growing with progress to build tension for "about to take effect"
  • Spring retreat: on an early release the fill springs back to 0 quickly (stiffness: 500, damping: 42)
  • Success state: a full fill triggers onConfirm, the button turns green, a checkmark draws itself in, and confirmedChildren is shown. The component stays in the success state afterwards; to replay it, change the key to remount (see the demo)
  • Keyboard support: space bar keydown starts the fill and keyup cancels it, matching the mouse press-and-hold behavior; e.repeat is filtered out so holding it down does not fire repeatedly
  • Accessibility: a "hold to confirm" description is attached with aria-describedby, and success is announced through aria-live="polite"
  • When the user has "reduce motion" enabled at the system level: the hold duration and the linear fill are kept exactly as they are (functionality unchanged), and only the tremor is removed, with the retreat becoming a fast linear one
  • touch-none + select-none prevent a touch hold from triggering scrolling or text selection; the pointer leaving the button, the event being cancelled (pointercancel), or losing focus during a keyboard hold all count as a release and cancel it

On this page