crucıble

Ratchet

Hold-to-confirm button for destructive actions: pressing and holding (pointer or Space/Enter) advances a 24-tooth SVG ring tooth by tooth with a click-scale, releasing early ratchets it back down faster, and completion flashes the ring, morphs the icon into a check and fires onConfirm. Real button, aria-describedby hold hint, polite live announcement, stepped-opacity fill under reduced motion.

motionfree

Installation

CLI

npx shadcn@latest add @crucible/ratchet

Manual — install dependencies, then copy the source

npm install motion

Props

PropTypeDefaultDescription
childrenReact.ReactNode"Hold to confirm"Idle label, shown to the right of the toothed ring.
confirmedLabelReact.ReactNode"Confirmed"Label shown (and politely announced) after the hold completes.
holdMsnumber1200Milliseconds of continuous holding needed to fill all 24 teeth.
onConfirm() => voidFires once when the ring completes. Never fires on an early release.
latchbooleanfalseStay in the confirmed state instead of resetting after 1.6s (call ref.reset() to clear).
toneRatchetTone"danger"Accent family: danger is rust, neutral is graphite.
accentColorstringOverride the tone's accent color (any CSS color).
iconReact.ReactNodea trash glyph (danger) or an up-arrow (neutral)Icon inside the well.
disabledbooleanfalseReally disable the button.
refReact.Ref<RatchetHandle>Imperative handle: { reset() }.
Also accepts all props of Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, OwnedHandlers> — they pass through to the underlying element.

Honors prefers-reduced-motion with a designed static fallback, and passes className through.