# Delete Button

> Two-step delete: first click arms it, a second click within 3s confirms; blur cancels.

- Author: Atelier UI
- License: MIT
- Page: https://chromotion.dev/en/components/delete-button
- Site: Atelier UI (https://chromotion.dev)

## Install

```bash
npx shadcn@latest add https://chromotion.dev/r/delete-button.json
```

Stack: React + TypeScript + Tailwind CSS v4, shadcn/ui conventions. `cn` comes from `@/lib/utils`.

## Dependencies

```bash
npm install lucide-react
```

## Usage

```tsx title="components/delete-button-demo.tsx"
import { DeleteButton } from "@/components/delete-button"

export default function DeleteButtonDemo() {
  return (
    <div className="flex flex-wrap items-center justify-center gap-4 p-8">
      <DeleteButton />
      <DeleteButton label="Remove project" confirmLabel="Really remove?" />
    </div>
  )
}
```

## Source

```tsx title="components/delete-button.tsx"
"use client"

import * as React from "react"
import { Trash2 } from "lucide-react"

import { cn } from "@/lib/utils"

export interface DeleteButtonProps extends Omit<React.ComponentProps<"button">, "children"> {
  label?: string
  confirmLabel?: string
  onDelete?: () => void
}

export function DeleteButton({
  label = "Delete",
  confirmLabel = "Click to confirm",
  onDelete,
  className,
  onClick,
  onBlur,
  ...props
}: DeleteButtonProps) {
  const [armed, setArmed] = React.useState(false)
  const timer = React.useRef<ReturnType<typeof setTimeout> | null>(null)

  React.useEffect(
    () => () => {
      if (timer.current) clearTimeout(timer.current)
    },
    []
  )

  function disarm() {
    if (timer.current) clearTimeout(timer.current)
    timer.current = null
    setArmed(false)
  }

  return (
    <button
      type="button"
      className={cn(
        "inline-flex h-10 items-center justify-center gap-2 rounded-lg border px-5 text-sm font-medium transition-all duration-200 active:scale-[0.97]",
        armed
          ? "border-destructive bg-destructive text-white shadow-[0_0_0_4px_color-mix(in_srgb,var(--destructive)_25%,transparent)]"
          : "border-destructive/40 bg-destructive/10 text-destructive hover:bg-destructive/20",
        "focus-visible:ring-2 focus-visible:ring-destructive focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:outline-none",
        "disabled:pointer-events-none disabled:opacity-50",
        className
      )}
      onClick={(event) => {
        onClick?.(event)
        if (armed) {
          disarm()
          onDelete?.()
        } else {
          setArmed(true)
          timer.current = setTimeout(() => setArmed(false), 3000)
        }
      }}
      onBlur={(event) => {
        disarm()
        onBlur?.(event)
      }}
      {...props}
    >
      <Trash2 className="size-4" />
      {armed ? confirmLabel : label}
    </button>
  )
}
```
