電商購物體驗

付款成功面板

底部付款面板的完整流程 React 元件:面板滑上、付款鈕縮成處理中圓環、圓環形變成勾並脈衝一次、訂單摘要依序展開。

結帳最後一步的底部面板。按下付款後,全寬的付款鈕寬度收合成 56px 的圓,裡面轉起進度環;付款成功時環收合、勾一筆畫出,整顆按鈕脈衝一次,接著標題換成「付款成功」,訂單編號、付款時間、預計到貨等摘要列以 70ms 間隔依序展開,最後呼叫 onDone。面板可拖曳把手往下關閉,處理中則鎖住所有關閉途徑。開啟狀態與付款階段各自支援受控/非受控雙模式。

把這個效果裝進你的專案

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

npx webberui@latest add payment-success-sheet

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

Playground

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

340
編輯中的呼叫預設屬性
<PaymentSuccessSheet/>

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

安裝

npx webberui@latest add https://webberui.com/r/payment-success-sheet.json

或在 components.json 設定 registries 後,改用 @webberui/payment-success-sheet 安裝。

使用

import { PaymentSuccessSheet } from "@/components/ui/payment-success-sheet";

<PaymentSuccessSheet
  items={[
    { id: "cushion", name: "亞麻抱枕套", qty: 1, price: 680 },
    { id: "tray", name: "手作木托盤", qty: 1, price: 600 },
  ]}
  total={1280}
  currency="TWD"
  paymentMethod="•••• 4242"
  summary={[
    { label: "訂單編號", value: "MB-20261025-0412" },
    { label: "合計", value: "NT$1,280" },
    { label: "預計到貨", value: "10/28(二)" },
  ]}
  onPay={async () => {
    // 呼叫你的金流 API;resolve 進入成功,reject 回到待付款
    await chargeCard();
  }}
  onDone={() => console.log("動畫結束,可以接著出單")}
/>

Props

Prop型別預設值說明
openboolean—受控的面板開啟狀態;未提供時由元件內部管理
defaultOpenbooleanfalse非受控模式的初始開啟狀態
onOpenChange(open: boolean) => void—開啟狀態變更時回呼
stage"idle" | "processing" | "success"—受控的付款階段;提供時由父層推進
defaultStage"idle" | "processing" | "success""idle"非受控模式的初始階段
onStageChange(stage: PaymentSuccessSheetStage) => void—付款階段變更時回呼
itemsPaymentSuccessSheetItem[]—購物清單
totalnumber—應付合計
currencystring"TWD"幣別代碼,決定金額前綴(TWD → NT$、USD → $、JPY → ¥、EUR → €、HKD → HK$,其他直接顯示代碼)
paymentMethodReactNode—付款方式列內容;未提供則不顯示該列
summaryPaymentSuccessSheetSummaryRow[]付款方式+合計成功後依序展開的摘要列
onPay() => Promise<void> | void—按下付款鈕時呼叫;非受控時 resolve 進入 success、reject 回到 idle
onDone() => void—成功動畫與摘要全部展開後呼叫
stiffnessnumber340面板滑上 spring 的 stiffness(damping 固定 34)
showToastbooleantrue成功後在面板上方浮出「已加入訂單」提示 2 秒
showTriggerbooleantrue是否顯示內建的「前往結帳」觸發鈕
containedbooleanfalse面板定位在最近的 positioned 祖先內,且不鎖 body 捲動(適合示範框、預覽)
labelsPartial<PaymentSuccessSheetLabels>—介面文字覆寫
classNamestring—追加到根元素

PaymentSuccessSheetItem

欄位型別預設值說明
idstring—唯一識別
namestring—商品名稱
qtynumber—數量
pricenumber—單價;列上顯示單價 × 數量
thumbReactNode名稱首字方塊縮圖

PaymentSuccessSheetSummaryRow

欄位型別預設值說明
labelstring—摘要列標題
valueReactNode—摘要列內容

PaymentSuccessSheetLabels

欄位型別預設值說明
triggerstring"前往結帳"內建觸發鈕文字
titlestring"確認付款"付款前標題
successTitlestring"付款成功"成功後標題
paystring"付款"付款鈕前綴,後接合計金額
processingstring"付款處理中"處理中的螢幕閱讀器宣告
processingButtonstring"處理中…"減少動態效果時按鈕上的文字
successstring"付款成功"成功的螢幕閱讀器宣告
paymentMethodstring"付款方式"付款方式列標題
totalstring"合計"合計列標題
closestring"關閉"關閉鈕的無障礙名稱
dragHandlestring"往下拖曳以關閉"拖曳把手提示
toaststring"已加入訂單"成功提示文字

細節

  • 節奏:面板以 spring(stiffness 預設 340、damping 34)從底部滑上,遮罩 200ms 淡入;付款鈕寬度 morph 用 bounce 0、0.26 秒的 spring;勾 400ms 畫出、脈衝 500ms(scale 1 → 1.12 → 1,外圈擴散淡出)。
  • 成功色走 CSS 變數 --wb-pss-success(預設 #10b981),可在主題層覆寫。
  • 非受控時處理中至少停留 0.8 秒,避免 onPay 太快 resolve 讓進度環一閃而過;受控時元件只通知 onStageChange("processing"),由你決定何時切到 success。
  • 非受控模式下,成功後關閉面板會重置回 idle,下次打開是新的一筆結帳。
  • 拖曳只從頂部把手啟動:往下超過 100px 或速度超過 500px/s 即關閉,未達門檻彈回。
  • 想在付款成功後出一張收據,可把同批次的 receipt-printer(Pro)接在 onDone 之後;本元件不依賴它。
  • 金額格式化是確定性的(自行加千分位,不用 Intl.NumberFormat),伺服器與瀏覽器輸出一致,不會造成 hydration 不一致。

可及性

  • 面板為 role="dialog"、aria-modal="true",以 aria-labelledby 指向標題;開啟時焦點移到付款鈕,Tab/Shift+Tab 鎖在面板內,關閉後焦點回到開啟前的元素
  • Esc、點遮罩、拖曳把手、關閉鈕都能關閉面板;付款處理中這些途徑全部停用
  • 付款鈕處理中設定 aria-busy 並停用,縮成圓形時以 aria-label 保留可讀名稱
  • 隱藏的 role="status"、aria-live="polite" 區域依序宣告「付款處理中」「付款成功」
  • 使用者系統開啟「減少動態效果」時,面板改為 150ms 淡入、付款鈕不 morph 而是直接換成「處理中…」文字、勾直接出現且不脈衝、摘要列直接顯示、停用拖曳