DoubtButton

DoubtButton never lets you click just once. Each press swaps the label for the next, increasingly absurd confirmation prompt, shakes, and bleeds a little more red. A row of dots tracks how much doubt you have left to power through. Only the click on the final prompt fires onConfirm.

Preview

DoubtButton

Keep clicking through the doubt

Variants

One quick doubt

Pass a single confirmation for a lightweight "are you sure?" gate.

One doubt

Two clicks total

Maximum dread

A longer chain for the truly irreversible.

Maximum dread

Push through every doubt

Install

Add the item with the shadcn CLI.

npx shadcn@latest add @evilbuttons/doubt-button

Usage

[]txt
import { DoubtButton } from "@/components/evil-buttons/doubt-button";

export function ButtonDemo() {
  return (
    <DoubtButton
      label="Delete everything"
      successLabel="Too late."
      onConfirm={() => wipeDatabase()}
    />
  );
}

Props

The component spreads any <button> HTML attributes except onClick.

PropTypeDefaultDescription
childrenReact.ReactNode-Label shown in the idle state. Falls back to label.
labelReact.ReactNode"Delete everything"Idle label used when no children are provided.
confirmationsReact.ReactNode[]6 escalating promptsPrompts shown one per click; the last one fires the action.
successLabelReact.ReactNode"Too late."Label flashed after the final confirmation.
onConfirm() => void-Fired only after the last confirmation is clicked.
resetAfternumber1600Milliseconds to stay in the success state before resetting. Set to 0 to stay.
classNamestring-Extra classes passed to the button.

Notes

  • The user must click confirmations.length + 1 times before onConfirm runs; an empty confirmations array makes it behave like a normal one-shot button.
  • The accent escalates from a calm tint toward blood-red as you advance, and the button shakes on every click via Motion.
  • An invisible copy of the widest prompt reserves the button's width so the layout never jumps as labels swap.
  • A row of dots fills in to show how many doubts you have answered out of the total.
  • aria-live="polite" and data-state (idle | doubting | success) expose the current state for screen readers and styling.

Registry

The registry item includes components/evil-buttons/doubt-button.tsx and installs clsx, tailwind-merge, and motion as dependencies.