Frontend Lab
← 回到所有模式
PA08🧩 Compose · 互動組合通知

Toast / Notification

Toast 通知

難度 ★★★★★標籤 toast · stack · auto-dismiss3 min read

模式簡述

Toast 看似簡單,做到「好用」其實要顧很多細節:堆疊上限、auto-dismiss 時長、錯誤不要自動消失、 mobile 出現位置。這裡先做核心堆疊行為,正式用建議直接套 sonner。

尚無 toast

|無 toast

Claude Code Prompt

💬 Claude Code Prompt
參考:PA08 toast
技術:堆疊定位 + 自動消失

具體行為:
- 位置:右下角(mobile 改頂部)
- 堆疊:最多 3 條,超過自動移除最舊的
- 視覺:堆疊時後面的縮小 + 上移(透視感)
- success: 3 秒自動消失
- info: 4 秒
- error: **不自動消失**,使用者必須手動關
- 每個都有 × 可關閉
- 點 × 用 fade + slide-out

限制:
- 錯誤千萬不要 auto-dismiss,使用者錯過會找不到原因
- 堆疊上限 3 條,多了會炸版面
- 不要堆同類訊息(重複「儲存中」就 dedupe)

完整程式碼

ToastStack.tsx
'use client'

import { useState, useCallback } from 'react'

type Toast = { id: number; variant: 'success'|'info'|'error'; title: string; desc?: string }

export function useToasts() {
const [toasts, setToasts] = useState<Toast[]>([])

const push = useCallback((t: Omit<Toast, 'id'>) => {
  const id = Date.now()
  setToasts(prev => [...prev.slice(-2), { ...t, id }])
  if (t.variant !== 'error') {
    setTimeout(() => {
      setToasts(prev => prev.filter(x => x.id !== id))
    }, t.variant === 'success' ? 3000 : 4000)
  }
}, [])

return { toasts, push }
}

export function ToastStack({ toasts }: { toasts: Toast[] }) {
return (
  <div className="fixed bottom-3 right-3 flex flex-col-reverse gap-1.5">
    {toasts.map((t, i) => {
      const offset = (toasts.length - 1 - i) * 6
      const scale = 1 - (toasts.length - 1 - i) * 0.04
      return (
        <div
          key={t.id}
          style={{ transform: `translateY(-${offset}px) scale(${scale})` }}
        >
          {t.title}
          <button>×</button>
        </div>
      )
    })}
  </div>
)
}

何時用

  • ✅ 操作成功 / 失敗的非阻擋回饋(儲存、複製、送出)
  • ✅ 背景任務狀態(上傳完成、deploy 結束)
  • ✅ 系統通知(連線斷開、新訊息)

何時別用

  • ❌ 需要使用者決策(用 dialog / confirm)
  • ❌ 關鍵錯誤訊息(用 banner / dialog,toast 太短暫)
  • ❌ 表單欄位錯誤(inline 顯示,不要 toast)

我踩過的坑

  1. 錯誤 toast 自動消失:使用者轉頭 3 秒就沒了,後來不知道發生啥。 錯誤 toast 一定要使用者手動關。

  2. 堆疊上限沒設:點儲存 10 次,畫面變成 toast 山。設上限 3 條最舒服。

  3. mobile 也放右下:iPhone safe area + tab bar 把 toast 擠到看不見。 mobile 改放頂部,跟通知欄習慣一致。

相關模式

  • 暫無

搜尋

按 ⌘K 隨時開啟