Popover/DropdownMenu 浮層選單
錨定在觸發元素旁的兩種浮層:Popover 裝內容,DropdownMenu 裝動作。
在 Storybook 開啟用途
| 元件 | 裝什麼 | 典型場景 |
|---|---|---|
Popover | 一小塊就地內容 | 表格的 faceted 篩選面板、欄位說明、迷你設定 |
DropdownMenu | 一組動作或開關 | 列操作選單(⋯)、欄位顯示切換、側欄收合態的子選單 |
判準:按下去會發生事情的是選單項,攤開來看的是面板。 兩個混用的症狀是「選單裡出現輸入框」或「面板裡整排按鈕」。
何時不要用
✅ 這樣做
就地的小決定:篩選、切換、單筆操作。開著浮層時背景仍看得到、仍有脈絡。
🚫 不要這樣
要使用者做完整決定的內容(確認後果、填表單)不要塞浮層—— 用 Dialog。浮層點外面就散掉, 填到一半消失的表單是最惹人厭的表單。
✅ 這樣做
DropdownMenu 保持單層。目前全書沒有任何場景需要子選單—— 連頂部的功能選單列也是一層,兩層群組用分區標題分開。
🚫 不要這樣
不要做巢狀選單。滑鼠要沿著走廊走直角的選單,是桌面軟體的遺物, 在觸控裝置上完全不能用。動作多到需要分層,代表該收斂動作,不是加層。
狀態
彈出面板:就地篩選
下拉選單:列操作
勾選項預設不關閉選單
DropdownMenuCheckboxItem 勾選後選單留在原地——連續切換多個開關
(例如欄位顯示)是它存在的理由,每勾一下就關等於逼使用者重開 N 次。
要恢復「選了就關」,傳自己的 onSelect 蓋掉即可。
✅ 這樣做
破壞性動作放選單最下面、加 text-destructive,並在點擊後走
ConfirmDialog 的分級確認。
🚫 不要這樣
不要把「刪除」跟「編輯」排在相鄰兩行的中間位置——選單是肌肉記憶操作, 手滑的代價要與位置的順手程度成反比。
無障礙
- Radix 保證:焦點管理、方向鍵移動(DOM 焦點跟著走)、Esc 關閉、焦點歸還觸發鈕、
role="menu"與aria-checked。 - 選單項的 highlight 走狀態層的已選強度——「按 Enter 會執行這個」比 「這個可以互動」強一階,與 Select 同一條規則。
- 圖示型觸發鈕(⋯)必須有
aria-label:「更多操作」不是裝飾。
取用
npx shadcn@latest add https://kielchang.github.io/dooping-design-book/r/popover.json
npx shadcn@latest add https://kielchang.github.io/dooping-design-book/r/dropdown-menu.json
Collapsible(摺疊區)與 Separator(分隔線)同批收錄,是這兩個浮層與側欄的組合零件:
npx shadcn@latest add https://kielchang.github.io/dooping-design-book/r/collapsible.json
npx shadcn@latest add https://kielchang.github.io/dooping-design-book/r/separator.json