Hold to confirm

Confirm a destructive action by holding, not tapping.

holdlong pressconfirm
Preview
Hold to confirm preview
Press and hold for 1.2 seconds to confirm. With a keyboard, hold Space or Enter.

When to use

  • Destructive actions like delete or revoke where the consequence is already visible on screen.
  • Replacing a confirm dialog with a deliberate press in compact settings rows.
  • Actions that should not fire on an accidental tap on touch devices.

When not to use

  • Use dialog when people need to read what will happen before confirming.
  • Use button or action-button for safe, easily undone actions.
  • Use swipe-actions for delete in touch lists.

shadcn CLI

Also installs (1)

  • manicat-foundation
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "hold-to-confirm",
  "type": "registry:ui",
  "title": "Hold to confirm",
  "description": "Confirm a destructive action by holding, not tapping.",
  "categories": [
    "actions"
  ],
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json"
  ],
  "files": [
    {
      "path": "registry/components/hold-to-confirm/hold-to-confirm.tsx",
      "type": "registry:component",
      "target": "@components/manicat/hold-to-confirm/hold-to-confirm.tsx"
    },
    {
      "path": "registry/components/hold-to-confirm/hold-to-confirm.module.css",
      "type": "registry:component",
      "target": "@components/manicat/hold-to-confirm/hold-to-confirm.module.css"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/hold-to-confirm",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/hold-to-confirm",
    "markdown": "https://uiarc.dev/components/hold-to-confirm/markdown",
    "tags": [
      "hold",
      "long press",
      "confirm"
    ]
  }
}

Usage

Install the component, then copy this into your app. Change the content and the props to fit your screen.

example.tsxtsx
"use client";

import { useEffect, useState } from "react";
import { HoldToConfirm } from "@/components/manicat/hold-to-confirm/hold-to-confirm";

export function HoldToConfirmExample() {
  const [confirmed, setConfirmed] = useState(false);

  return (
    <div className="flex flex-wrap items-center gap-3">
      <HoldToConfirm label="Hold to delete" onConfirm={() => setConfirmed(true)} />
      {confirmed ? <span className="text-sm text-(color:--text-muted)">Deleted.</span> : null}
    </div>
  );
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

Hold to delete A destructive action that needs an intentional press, with the result shown next to it.

Hold to delete A destructive action that needs an intentional press, with the result shown next to it. preview
Press and hold for 1.2 seconds to confirm. With a keyboard, hold Space or Enter.

Keyboard interactions

KeysAction
Space / Enter (hold)Fills the button; releasing early rewinds it.
Tab awayCancels an active hold.

Accessibility

  • aria-describedby points to a hidden hint: "Press and hold for N seconds to confirm. With a keyboard, hold Space or Enter."
  • aria-label tracks the visible label; a role="status" region announces confirmedLabel.
  • Once done the button sets aria-disabled; the text is drawn twice so it changes color exactly at the fill edge.

Motion

  • The fill advances on a linear timeline while held, rewinds on a smooth spring when released, and resumes from where it was on a quick re-press.
  • The button presses to about 0.97; on completion the label morphs, the width springs, and a check draws itself in. Touch devices get a short vibration.
  • Reduced motion drops the press scale and rewind spring and swaps label and icon with a fade; the fill still tracks the hold.

Responsive behavior

  • Uses pointer events with capture, so mouse, pen, and touch holds all work; sliding more than 24px off the button cancels the hold.
  • Touch holds trigger a short vibration on completion where the device supports it.
  • Keyboard users hold Space or Enter, and a hidden hint explains the duration.

Performance

  • The fill runs on a single linear motion animation, not a React state update per frame.
  • The label is drawn twice to change color at the fill edge; a ResizeObserver handles the width spring on completion.

Notes for AI

  • Use for destructive or hard-to-undo actions when the consequence is already visible on screen. Use dialog when people need to read what will happen first.
  • Write the label as an instruction ("Hold to …"); pass confirmed to reset it after an undo or a failed request.
  • Pair with onHoldChange to show a nearby hint while the press is held.