跳至主要内容
💬 回報這一頁

Dialog 對話框

打斷使用者,要一個決定。

在 Storybook 開啟

何時不要用

✅ 這樣做

破壞性動作的二次確認、需要專注填寫的小表單。

🚫 不要這樣

不要拿來裝大型表單或多步驟流程——對話框裡沒有麵包屑、不能深連結、 在手機上幾乎不能用。那應該是一個頁面。

破壞性動作確認

標題問問題,按鈕給答案

✅ 這樣做

標題:「確定要作廢 R-2403?」
按鈕:「確定作廢」/「返回」

🚫 不要這樣

標題:「確認」,按鈕:「是」/「否」。使用者滑掉上下文之後, 「是」是指是要取消還是是要保留?

按鈕文字要能單獨讀懂——很多人只看按鈕不看標題。

破壞性動作分三級

「破壞性動作要二次確認」講得太粗。每一個刪除都跳確認,使用者三天後就會閉著眼睛按確定—— 確認框變成儀式,就不再有保護作用了。

分三級,依「後果能不能復原」決定:

級別判準做法
可復原、影響單筆直接執行 + 就地提供「復原」。不要跳對話框
不可復原、影響單筆對話框確認。標題寫出對象與後果
不可復原、影響多筆或他人對話框 + 要求輸入辨識碼(編號、代號)才啟用確認鈕
✅ 這樣做

高風險才用「輸入名稱以確認」。它的作用是強迫閱讀—— 使用者為了打對那串字,一定得先看清楚自己在刪什麼。

🚫 不要這樣

不要對所有刪除都用這招。全部都要打字=使用者去背下那串字的規律, 保護作用歸零,只剩下惹人厭。

高風險對話框應同時列出受影響範圍(「將取消 12 筆已確認項目」), 而不是只說「此動作無法復原」。使用者需要的是「我會失去什麼」,不是恐嚇。

高風險:輸入編號才能確認

行動版是置中卡片,不是全螢幕

後台對話框通常是「確認一件事」,全螢幕會讓使用者失去背景脈絡 (他正在看的那一列到底是誰)。所以留邊距、維持置中。

長內容要在內容區捲動,標題與按鈕不動

對話框沒有高度上限時,內容一長就會往上下兩端撐出視窗(因為它是垂直置中的)。 結果是標題和按鈕同時被推出畫面外:使用者既看不到自己在確認什麼,也按不到確認鈕, 只剩下 Esc 一條路——而他多半不知道可以按 Esc。

✅ 這樣做

限制整體高度,讓只有內容區捲動。標題與按鈕固定可見。

🚫 不要這樣

不要讓整個對話框跟著頁面捲。使用者捲到底才發現按鈕在那裡, 而捲的過程中標題已經看不見了。

<DialogContent className="max-h-[85dvh] grid-rows-[auto_minmax(0,1fr)_auto]">
<DialogHeader>
<DialogTitle>調整 B-2403 的項目</DialogTitle>
</DialogHeader>

{/* 只有這一段捲動 */}
<div className="min-h-0 overflow-y-auto pr-1">
…長內容…
</div>

<DialogFooter></DialogFooter>
</DialogContent>

三個細節,缺一個就會出問題:

細節為什麼
dvh 而非 vh行動瀏覽器的網址列會伸縮。用 vh 會讓按鈕躲在網址列後面,怎麼點都點不到
min-h-0grid/flex 子項的預設最小高度是內容高度,不加這行 overflow 完全不會生效。這是最常見的「我明明寫了 overflow-y-auto」原因
85% 而非 100%留一點背景可見,使用者才知道自己在浮層裡、關掉會回到哪裡
✅ 這樣做

內容捲動時,在捲動區上下緣留出視覺線索(陰影或分隔線), 讓使用者知道下面還有東西。

🚫 不要這樣

不要讓內容剛好在邊界處切齊。切齊看起來就是結束了, 使用者不會想去捲——然後就漏看下半段。

需要捲很久,就不該是對話框了

這條規範的目的是處理「小表單長了一點」,不是讓對話框變成頁面。

✅ 這樣做

捲動內容超過約兩個畫面高 → 改成獨立頁面。

🚫 不要這樣

不要把多步驟流程塞進捲動的對話框。裡面沒有麵包屑、不能深連結、 中途離開就全部重來。

不要巢狀對話框

從對話框裡開另一個對話框,會有三個問題同時發生:

  1. Esc 語意不明——關掉哪一層?使用者按下去之前不知道,按下去之後也常常沒發現關錯了
  2. 焦點鎖定互相打架——兩層 focus trap 疊在一起,鍵盤使用者可能被困在中間層
  3. 背景疊兩層遮罩——畫面幾乎全黑,失去「我原本在看哪一列」的脈絡
✅ 這樣做

需要二次確認時,換掉同一個對話框的內容 (同一層走兩個步驟),或先關閉第一層再開第二層。

🚫 不要這樣

不要疊。唯一可接受的例外是 Select/Tooltip 這類浮層, 它們不是模態、不搶焦點鎖定。

無障礙

Radix Dialog 已處理焦點鎖定、Esc 關閉、aria-modal、還原焦點。 務必提供 DialogTitle——沒有標題的 modal 對螢幕報讀器是一片空白。

取用

npx shadcn@latest add https://kielchang.github.io/dooping-design-book/r/dialog.json