互動編排

鍵盤回應卡堆

一疊待回應的卡片,按數字鍵 1、2、3 直接選擇答案,卡片帶著選項方向飛走、下一張補位,鍵盤優先、滑鼠也能點。

適合待審清單、代理建議、批次確認這類「一張一張快速決定」的情境。最上面一張完整顯示,後面兩張依序往下露邊;焦點在卡堆上時按數字鍵 1–3 選擇對應選項(也可直接點按鈕),鍵帽會先按下、選項高亮,接著卡片朝選項方向飛出(1 左上、2 上、3 右上),後面的卡往前補位。Backspace 或 Ctrl+Z 可撤銷上一張,卡片會沿原方向飛回。全部回答完顯示摘要與每個選項的計數。回答紀錄支援受控/非受控雙模式。

把這個效果裝進你的專案

在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。

npx webberui@latest add keystroke-card-deck

還沒有專案,或安裝遇到問題?看快速開始 →

Playground

即時調整 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型別預設值說明
cardsKeystrokeCard[]—要逐一回應的卡片,依陣列順序由上而下
defaultOptionsKeystrokeCardOption[]核准/稍後/略過卡片沒有指定 options 時使用的預設選項
onAnswer(cardId: string, optionKey: string) => void—每回答一張卡時回呼
onComplete(answers: KeystrokeCardAnswers) => void—全部卡片都回答完時回呼,參數為完整回答紀錄
answersKeystrokeCardAnswers—受控的回答紀錄;未提供時由元件內部管理(非受控)
defaultAnswersKeystrokeCardAnswers{}非受控模式的初始回答紀錄
onAnswersChange(answers: KeystrokeCardAnswers) => void—回答紀錄變動時回呼(回答與撤銷都會觸發)
globalbooleanfalse監聽整個視窗的按鍵,焦點不在卡堆上也能用數字鍵回應
undobooleantrue允許以 Backspace/Ctrl+Z 撤銷上一張
visibleStacknumber3同時露出的卡片數(含最上方一張)
summaryReactNode | ((answers: KeystrokeCardAnswers) => ReactNode)「已處理 N 張」與各選項計數全部回答完後顯示的內容
stiffnessnumber340飛出與補位的彈簧剛性(damping 固定 30),數字越大節奏越快
accentstring—強調色,覆寫 --wb-keystroke-deck-accent
labelstring"待回應卡片"卡堆區域的無障礙名稱
classNamestring—透傳到最外層容器

KeystrokeCard

欄位型別預設值說明
idstring—卡片唯一識別值
titlestring—問題標題
bodyReactNode—內文
optionsKeystrokeCardOption[]—這張卡的選項(2–4 個);未提供時使用 defaultOptions

KeystrokeCardOption

欄位型別預設值說明
keystring—選項識別值,會寫進 answers 並傳給 onAnswer
labelstring—選項顯示文字
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 張」之類的訊息
  • 點選項按鈕回答時,焦點會先交回卡堆容器,避免卡片卸載後焦點遺失
  • 使用者系統開啟「減少動態效果」時,卡片直接淡出、下一張直接到位,不做飛出與彈簧補位