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

Toast 操作回饋

「你剛剛那個動作,成了沒」——只回答這一句的浮動訊息。

頁面章的跨頁守則說「操作回饋的去向全站固定一種」;固定的那一種就是本頁。 要改去向或時長,先改這頁的規範,再改元件常數——不要在個別畫面各自發明。

操作回饋(點按鈕試試;danger 不會自動消失)
在 Storybook 開啟

全站固定的那一種

規則為什麼
去向視窗右下不遮頁首動作列與側欄導覽;閱讀動線的終點
堆疊上限3,最舊被擠出連發不會疊出一面牆;重要到不能被擠出的訊息該用 Dialog
自動消失successinfowarning 5 秒,hover/聚焦暫停成功不需要人手;暫停是給「正在讀」的人
danger不自動消失,手動關閉錯誤不能自己溜走——使用者離開座位回來還看得到
分級Callout 同源:同圖示表、同淡底同一語意全站同一張臉,不靠顏色單獨傳達
讀屏一般 statuspolite;danger alertassertive成功不打斷朗讀,錯誤立即播報
層級z-[70]高於 Dialog(z-50)與資料表篩選面板(z-[60]

什麼不該用 Toast

✅ 這樣做

「動作的結果」:已儲存、已匯出、已加入排程、儲存失敗。

🚫 不要這樣

表單驗證錯誤不進 Toast。錯誤訊息貼著欄位 (aria-describedby),跨欄彙總用頁內 Callout—— 訊息會消失的地方,放不下需要對照著改的內容。

✅ 這樣做

一句話講完。標題一行、說明至多兩行。

🚫 不要這樣

不要放連結與多個動作。需要導向的結果(「檢視匯入紀錄」)用頁內 Callout 或直接導頁;Toast 會消失,放連結等於出考題。

與 Callout 的分工

兩者共用同一組語意表面(STATUS_SUBTLE_SURFACE),差別只在去向與壽命

ToastCallout
位置固定右下,浮在內容上就地,跟著內容捲動
壽命幾秒(danger 例外)持續存在
適用動作回饋規則說明、欄位彙總、需要對照的訊息

先前「Calloutlive」的替代用法在就地回饋的場合仍然正確 (例如儲存後表單頂部的長駐結果);要消失的動作回饋才搬到 Toast。

安裝與掛法

// 應用最外層包一次;viewport 由 Provider 自帶
<ToastProvider>
<App />
</ToastProvider>

// 任何元件內
const { push } = useToast();
push({ variant: "success", title: "已儲存" });
npx shadcn@latest add https://kielchang.github.io/dooping-design-book/r/toast.json

Toast 內容 portal 到 body 直下——嵌進自帶 CSS 的宿主時, 樣式基座必須涵蓋 portal(見 ADR-0010)。