{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "confirm-button",
  "title": "Confirm Button",
  "description": "Inline two-step confirmation on the button itself: the first click arms it — the label swaps to \"Confirm?\" and the button turns destructive — and only the second click calls onConfirm. It disarms itself after a timeout (3s by default) and on blur, so a stray double-click, a scroll away, or a Tab out can never fire the action. Reach for it wherever a modal would outweigh the action: a delete or remove button in a table row, a card, a list item or a toolbar; removing a member or collaborator; revoking an API key, token or session; disconnecting an integration; clearing a cache or a log; unsubscribing; resetting a filter or a setting; discarding a draft; leaving a channel. Common asks it answers: \"confirm before delete without a dialog\", \"two-step delete button react\", \"click twice to confirm\", \"are you sure button shadcn\", \"inline confirmation button\", \"destructive button with confirmation\", \"delete button in a table row\", \"undo-less delete confirmation\". Props: `onConfirm` (fired only on the confirming click), `confirmText` for the armed label, `timeout` in milliseconds, plus everything else a `<button>` takes. It is one real `<button>` element — Enter and Space confirm it, `disabled` is honoured, your `className` is merged through `cn`, and it defaults to `type=\"button\"` so an armed click inside a form cannot submit it by accident. The armed state is exposed as `data-armed` for styling and announced through a polite live region, so the change is never carried by colour and label alone. Theme-aware through the destructive tokens, no dependencies, and `\"use client\"` because it holds a state and a timer. What official shadcn/ui offers instead is alert-dialog: a modal that pulls in @radix-ui/react-alert-dialog, renders through a portal, traps focus and needs open state wired up — right for a page-level, consequential confirmation, heavy for a row-level one. Official button has a destructive variant but no confirmation behaviour at all. For an action severe enough that a second click is not enough — deleting a production project or an account — use type-to-confirm, which makes the user type the name first.",
  "dependencies": [],
  "files": [
    {
      "path": "registry/ui/confirm-button.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface ConfirmButtonProps\n  extends Omit<React.ComponentPropsWithoutRef<\"button\">, \"onClick\"> {\n  /** Called only on the second (confirming) click. */\n  onConfirm: () => void\n  /** Label shown after the first click while awaiting confirmation. */\n  confirmText?: string\n  /** How long (ms) the armed state stays before reverting to idle. */\n  timeout?: number\n}\n\nexport function ConfirmButton({\n  onConfirm,\n  confirmText = \"Confirm?\",\n  timeout = 3000,\n  children,\n  className,\n  disabled,\n  ...props\n}: ConfirmButtonProps) {\n  const [armed, setArmed] = React.useState(false)\n\n  React.useEffect(() => {\n    if (!armed) return\n    const id = window.setTimeout(() => setArmed(false), timeout)\n    return () => window.clearTimeout(id)\n  }, [armed, timeout])\n\n  function onClick() {\n    if (armed) {\n      setArmed(false)\n      onConfirm()\n    } else {\n      setArmed(true)\n    }\n  }\n\n  return (\n    <button\n      type=\"button\"\n      disabled={disabled}\n      onClick={onClick}\n      onBlur={() => setArmed(false)}\n      data-armed={armed || undefined}\n      className={cn(\n        \"inline-flex h-9 items-center justify-center rounded-md px-4 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50\",\n        armed\n          ? \"bg-destructive text-destructive-foreground hover:bg-destructive/90 focus-visible:ring-destructive\"\n          : \"border border-input bg-background hover:bg-accent hover:text-accent-foreground focus-visible:ring-ring\",\n        className\n      )}\n      {...props}\n    >\n      <span aria-live=\"polite\" className=\"sr-only\">\n        {armed ? \"Press again to confirm\" : \"\"}\n      </span>\n      {armed ? confirmText : children}\n    </button>\n  )\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}