PF04▸💬 Feedback · 反饋▸確認
Confirm Dialog
確認對話框
難度 ★★★★★標籤 confirm · destructive · 焦點3 min read
模式簡述
Confirm Dialog:執行破壞性動作前的二次確認。刪除、登出、發送都會用。要把後果寫清楚。
刪除專案
此操作無法復原,所有資料將永久刪除。
Claude Code Prompt
參考:PF04 confirm 組件:ConfirmDialog.tsx Confirm Dialog:執行破壞性動作前的二次確認。刪除、登出、發送都會用。要把後果寫清楚。 限制: - 按鈕標籤寫「確定/取消」 - 主按鈕預設 focus 危險選項 - 沒 loading state
完整程式碼
"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)
我踩過的坑
-
按鈕標籤寫「確定/取消」:使用者忘了在確認什麼。要寫「刪除帳號 / 取消」。
-
主按鈕預設 focus 危險選項:應該 default focus 在「取消」,避免誤按 Enter。
-
沒 loading state:點刪除後使用者狂點,重複觸發。disabled + spinner。
相關模式
- PB01
- PA08