電商購物體驗

交易清單

金融 App 式交易清單 React 元件:依日期自動分組為今天、昨天與完整日期,金額逐位滾動並以正負上色,新交易插入時高度展開、鄰列順移,右滑或按圖釘即可置頂,附處理中、失敗、已退款狀態標籤。

銀行與記帳 App 首頁那種交易清單。把交易陣列丟進來,元件依本地日期自動分組(「今天」「昨天」,其餘如「10月23日 週五」,跨年加年份),組內依時間新到舊排列;每列左側是圓形圖示或依標題首字產生的字母頭像,右側是逐位滾動的金額——收入加「+」並上色、支出保持中性——以及處理中、失敗、已退款的狀態標籤。新交易插入時該列高度展開、下方的列平順下移;向右滑動任一列或按右側圖釘可把它釘到最上方的「已釘選」組,以 layout 動畫飛過去。釘選狀態支援受控/非受控雙模式。

把這個效果裝進你的專案

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

npx webberui@latest add transaction-list

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

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

380
編輯中的呼叫預設屬性
<TransactionList/>

完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。

安裝

npx webberui@latest add https://webberui.com/r/transaction-list.json

或在 components.json 設定 registries 後,改用 @webberui/transaction-list 安裝。

使用

import { TransactionList } from "@/components/ui/transaction-list";

<TransactionList
  items={[
    { id: "1", date: "2026-10-23T09:00:00", title: "晨光設計有限公司", subtitle: "薪資入帳", amount: 52000 },
    { id: "2", date: "2026-10-23T14:20:00", title: "巷口便利商店", subtitle: "日用品", amount: -85, status: "pending" },
    { id: "3", date: "2026-10-22T19:30:00", title: "雲朵影音", subtitle: "月訂閱扣款", amount: -390, status: "failed" },
  ]}
  currency="TWD"
  defaultPinnedIds={["1"]}
  onSelect={(id) => console.log(`點選 ${id}`)}
/>

Props

Prop型別預設值說明
itemsTransactionItem[]—交易資料;順序不拘,元件會依時間新→舊排序
groupedbooleantrue是否依日期分組(今天/昨天/完整日期);關閉時為單一清單,副標改顯示日期
currencystring"TWD"預設幣別(ISO 4217),item 未指定 currency 時使用
pinnedIdsstring[]—受控的已釘選 id 清單;未提供時由元件內部管理(非受控)
defaultPinnedIdsstring[][]非受控模式的初始已釘選 id 清單
onPinnedChange(ids: string[]) => void—釘選狀態變動時回呼,參數為新的已釘選 id 清單
onSelect(id: string) => void—點選某列時回呼;提供後每列成為可聚焦的按鈕
stiffnessnumber380列位移、展開與金額滾動的 spring 剛度
emptyStateReactNode收據圖示 +「目前沒有交易紀錄」沒有任何交易時顯示的內容
nowDate—決定「今天/昨天」的基準時間;未提供時掛載後才以 new Date() 計算,首次渲染顯示完整日期
classNamestring—透傳到最外層容器

TransactionItem

欄位型別預設值說明
idstring—唯一識別碼;也用來確定性地決定字母頭像的底色
datestring | Date—交易時間(ISO 字串或 Date),依本地日期分組
titlestring—標題(商家或對象名稱)
subtitlestring—副標(類別、備註等),會與時間 HH:mm 並列
amountnumber—金額;正數為收入、負數為支出
currencystring元件的 currencyISO 4217 幣別代碼
status"completed" | "pending" | "failed" | "refunded""completed"交易狀態;completed 不顯示標籤
iconReactNode—左側 40px 圓形圖示;未提供時依標題首字產生字母頭像

細節

  • 金額以 Intl.NumberFormat("zh-TW") 格式化,台幣不顯示小數,其他幣別最多兩位;zh-TW 會把台幣顯示成「$」,元件改成「NT$」避免與美元混淆。
  • 逐位滾動:每一位數字是 0 到 9 的直列,以 spring(stiffness 與 damping 20)滾到目標值;NT$、逗號等非數字字元保持靜態。金額或幣別改變時從舊值滾到新值。
  • 新增與刪除:新列從高度 0 展開,下方的列與日期組跟著順移;被移除的列反向收合。釘選與取消釘選時,列以共用 layoutId 從原位置飛到新組,不做高度展開。
  • 右滑釘選:列可水平拖曳,左側露出「釘選」提示,放開時位移超過門檻就切換;拖曳過後的放開不會觸發 onSelect。
  • 顏色變數:收入色 --wb-txl-positive(深色模式 --wb-txl-positive-dark);狀態標籤 --wb-txl-pending、--wb-txl-failed、--wb-txl-refunded,各自有 -bg 與 -dark 版本。
  • SSR:沒有傳 now 時,首次渲染組標題一律顯示含年份的完整日期,掛載後才換成「今天/昨天」,避免伺服器與瀏覽器時間不同造成 hydration 不一致。

可及性

  • 每個日期組是 section,以 aria-labelledby 指向組標題;列是 ul/li
  • 傳入 onSelect 時每列是按鈕,aria-label 完整朗讀標題、收入或支出金額、日期時間與狀態,例如「巷口便利商店,支出 NT$85,今天 14:20,處理中」
  • 滾動中的數字對輔助科技隱藏,旁邊附上螢幕閱讀器專用的完整金額
  • 釘選按鈕以 aria-pressed 表示狀態,可用 Tab 聚焦並以 Enter/Space 切換;右滑只是額外的快捷操作
  • 新增交易時以 aria-live="polite" 宣告
  • 使用者系統開啟「減少動態效果」時:沒有進場 stagger、金額直接顯示不滾動、新增的列直接出現(高度不動畫)、釘選時直接換位