互動編排
鍵盤回應卡堆
一疊待回應的卡片,按數字鍵 1、2、3 直接選擇答案,卡片帶著選項方向飛走、下一張補位,鍵盤優先、滑鼠也能點。
適合待審清單、代理建議、批次確認這類「一張一張快速決定」的情境。最上面一張完整顯示,後面兩張依序往下露邊;焦點在卡堆上時按數字鍵 1–3 選擇對應選項(也可直接點按鈕),鍵帽會先按下、選項高亮,接著卡片朝選項方向飛出(1 左上、2 上、3 右上),後面的卡往前補位。Backspace 或 Ctrl+Z 可撤銷上一張,卡片會沿原方向飛回。全部回答完顯示摘要與每個選項的計數。回答紀錄支援受控/非受控雙模式。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add keystroke-card-deckPlayground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
3
340
編輯中的呼叫預設屬性
<KeystrokeCardDeck/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
安裝
npx webberui@latest add https://webberui.com/r/keystroke-card-deck.json或在 components.json 設定 registries 後,改用 @webberui/keystroke-card-deck 安裝。
使用
import { KeystrokeCardDeck } from "@/components/ui/keystroke-card-deck";
<KeystrokeCardDeck
cards={[
{ id: "dunning", title: "是否寄出催款提醒給 3 位客戶?", body: "三筆帳款已逾期 14 天。" },
{ id: "report", title: "把週報排程改到週五 17:00?" },
]}
onAnswer={(cardId, optionKey) => console.log(cardId, optionKey)}
onComplete={(answers) => console.log("全部完成", answers)}
/>Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
cards | KeystrokeCard[] | — | 要逐一回應的卡片,依陣列順序由上而下 |
defaultOptions | KeystrokeCardOption[] | 核准/稍後/略過 | 卡片沒有指定 options 時使用的預設選項 |
onAnswer | (cardId: string, optionKey: string) => void | — | 每回答一張卡時回呼 |
onComplete | (answers: KeystrokeCardAnswers) => void | — | 全部卡片都回答完時回呼,參數為完整回答紀錄 |
answers | KeystrokeCardAnswers | — | 受控的回答紀錄;未提供時由元件內部管理(非受控) |
defaultAnswers | KeystrokeCardAnswers | {} | 非受控模式的初始回答紀錄 |
onAnswersChange | (answers: KeystrokeCardAnswers) => void | — | 回答紀錄變動時回呼(回答與撤銷都會觸發) |
global | boolean | false | 監聽整個視窗的按鍵,焦點不在卡堆上也能用數字鍵回應 |
undo | boolean | true | 允許以 Backspace/Ctrl+Z 撤銷上一張 |
visibleStack | number | 3 | 同時露出的卡片數(含最上方一張) |
summary | ReactNode | ((answers: KeystrokeCardAnswers) => ReactNode) | 「已處理 N 張」與各選項計數 | 全部回答完後顯示的內容 |
stiffness | number | 340 | 飛出與補位的彈簧剛性(damping 固定 30),數字越大節奏越快 |
accent | string | — | 強調色,覆寫 --wb-keystroke-deck-accent |
label | string | "待回應卡片" | 卡堆區域的無障礙名稱 |
className | string | — | 透傳到最外層容器 |
KeystrokeCard
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
id | string | — | 卡片唯一識別值 |
title | string | — | 問題標題 |
body | ReactNode | — | 內文 |
options | KeystrokeCardOption[] | — | 這張卡的選項(2–4 個);未提供時使用 defaultOptions |
KeystrokeCardOption
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
key | string | — | 選項識別值,會寫進 answers 並傳給 onAnswer |
label | string | — | 選項顯示文字 |
direction | "left" | "up" | "right" | 依序號 | 選中後的飛出方向;未指定時 1 左上、2 上、3 之後右上 |
KeystrokeCardAnswers 是 Record<string, string>(卡片 id 對應選項 key)。
細節
- 節奏外露成 CSS 變數:
--wb-keystroke-deck-press(鍵帽按下,預設 80ms)、--wb-keystroke-deck-highlight(選項高亮到卡片飛出的間隔,預設 150ms)、--wb-keystroke-deck-accent(高亮色,預設#3b82f6)。 - 目前卡片 =
cards中第一張尚未回答的卡;撤銷依本元件內的回答順序回退,受控值被外部改動時改退回卡片順序中最後一張已回答的卡。 global模式下,焦點在 input、textarea、select 或 contenteditable 時不攔截按鍵;中文等輸入法組字中(isComposing或 keyCode 229)的按鍵一律忽略。- 卡片疊放用 CSS grid 同一格重疊,容器高度跟著最高的那張卡,不必寫死高度。
可及性
- 卡堆是
role="region",以aria-label命名,並用aria-describedby指向「按 1–3 回應」的說明 - 最上方卡片為
role="group";選項是button並帶aria-keyshortcuts,撤銷按鈕同樣可用滑鼠操作 - 非最上方的卡片設定
aria-hidden與inert,不會被 Tab 或螢幕閱讀器讀到 - 每次回答或撤銷,
aria-live區域宣告「已選擇:核准,剩 5 張」之類的訊息 - 點選項按鈕回答時,焦點會先交回卡堆容器,避免卡片卸載後焦點遺失
- 使用者系統開啟「減少動態效果」時,卡片直接淡出、下一張直接到位,不做飛出與彈簧補位