Frontend Lab
← 回到所有模式
PF04💬 Feedback · 反饋確認

Confirm Dialog

確認對話框

難度 ★★★★★標籤 confirm · destructive · 焦點3 min read

模式簡述

Confirm Dialog:執行破壞性動作前的二次確認。刪除、登出、發送都會用。要把後果寫清楚。

刪除專案

此操作無法復原,所有資料將永久刪除。

破壞性|刪除確認 — 紅色按鈕

Claude Code Prompt

💬 Claude Code Prompt
參考:PF04 confirm
組件:ConfirmDialog.tsx

Confirm Dialog:執行破壞性動作前的二次確認。刪除、登出、發送都會用。要把後果寫清楚。

限制:
- 按鈕標籤寫「確定/取消」
- 主按鈕預設 focus 危險選項
- 沒 loading state

完整程式碼

ConfirmDialog.tsx
"use client";
import { useEffect, useState } from "react";
import { AlertTriangle } from "lucide-react";

type State = "destructive" | "info" | "loading";

export function ConfirmDialog({ state = "destructive" }: { state?: State }) {
const [open, setOpen] = useState(true);
useEffect(() => setOpen(true), [state]);

const config =
  state === "info"
    ? { title: "確認儲存", desc: "你即將儲存 3 項變更,是否繼續?", btn: "儲存", color: "bg-lab-accent" }
    : { title: "刪除專案", desc: "此操作無法復原,所有資料將永久刪除。", btn: state === "loading" ? "刪除中⋯" : "刪除", color: "bg-red-500 hover:bg-red-600" };

return (
  <div className="relative h-64 w-full max-w-md overflow-hidden rounded-xl border border-border bg-background/30">
    <div className="absolute inset-0 bg-background/60 backdrop-blur-sm" />
    {open && (
      <div className="absolute left-1/2 top-1/2 w-72 -translate-x-1/2 -translate-y-1/2 rounded-lg border border-border bg-background p-5 shadow-2xl">
        <div className="mb-3 flex items-start gap-3">
          {state !== "info" && (
            <div className="grid h-8 w-8 shrink-0 place-items-center rounded-full bg-red-500/15">
              <AlertTriangle className="h-4 w-4 text-red-500" />
            </div>
          )}
          <div>
            <h3 className="text-sm font-medium">{config.title}</h3>
            <p className="mt-1 text-xs text-muted-foreground">{config.desc}</p>
          </div>
        </div>
        <div className="flex justify-end gap-2">
          <button className="rounded-md border border-border px-3 py-1.5 text-xs hover:bg-muted">
            取消
          </button>
          <button
            disabled={state === "loading"}
            className={`rounded-md px-3 py-1.5 text-xs text-white ${config.color} ${state === "loading" ? "opacity-70" : ""}`}
          >
            {config.btn}
          </button>
        </div>
      </div>
    )}
  </div>
);
}

何時用

  • ✅ 刪除(無法復原)
  • ✅ 登出、清除資料
  • ✅ 結帳、發送大規模通知

何時別用

  • ❌ 可復原的動作(用 toast + undo)
  • ❌ 頻繁操作(confirm fatigue)
  • ❌ 資訊只是 FYI(用 banner)

我踩過的坑

  1. 按鈕標籤寫「確定/取消」:使用者忘了在確認什麼。要寫「刪除帳號 / 取消」。

  2. 主按鈕預設 focus 危險選項:應該 default focus 在「取消」,避免誤按 Enter。

  3. 沒 loading state:點刪除後使用者狂點,重複觸發。disabled + spinner。

相關模式

  • PB01
  • PA08

搜尋

按 ⌘K 隨時開啟