WebberUI

免運門檻進度條(React)

多階門檻進度條(免運→贈品→折扣)的 React 元件:「再買 NT$X 即可享免運」差額逐位滾動、越過門檻整條變色、節點彈跳並噴出一次性小彩帶,已達成的階以 chip 列出,可獨立貼在購物車頂欄。

獨立於購物車的滿額門檻條:把 subtotaltiers(免運 → 贈品 → 折扣,依金額遞增)交給它,頂部文案就會顯示「再買 NT$X 即可享免運」,差額用逐位滾動的數字捲軸更新;軌道依階數等寬分段,每個門檻位置有一顆小圖示節點,未達灰、達成填色並彈跳一下;填色條以彈簧動畫推進,越過新門檻的瞬間整條換成該階顏色、節點噴出 10 顆小彩帶,下方 chip 同步打勾。全部達成時文案改為「已解鎖全部優惠」。compact 模式縮成一條薄軌,適合放在購物車或側欄的頂部。

載入預覽⋯
npx shadcn@latest add https://webberui.com/r/free-shipping-meter.json

Playground

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

640
990
<FreeShippingMeter />

安裝

npx shadcn@latest add https://webberui.com/r/free-shipping-meter.json

或在 components.json 設定 registries 後,改用 @webberui/free-shipping-meter 安裝。

使用

import { FreeShippingMeter } from "@/components/ui/free-shipping-meter";
import { Gift, Truck } from "lucide-react";

// 單階:只有免運門檻時,直接給 threshold
<FreeShippingMeter subtotal={640} threshold={990} />

// 多階:免運 → 贈品 → 折扣(依金額遞增)
<FreeShippingMeter
  subtotal={cartSubtotal}
  currency="NT$"
  tiers={[
    { amount: 990, label: "免運", icon: Truck, reward: "全館免運" },
    { amount: 1500, label: "贈品", icon: Gift, reward: "送帆布購物袋" },
    { amount: 2500, label: "折扣", reward: "結帳再折 NT$100" },
  ]}
  onTierReached={(tier, index) => console.log(`達成第 ${index + 1} 階:${tier.label}`)}
/>

// 購物車頂欄:精簡模式
<FreeShippingMeter subtotal={cartSubtotal} tiers={tiers} compact />

Props

Prop型別預設值說明
subtotalnumber0目前購物車小計;由外部提供,元件依此計算進度、文案與達標狀態
tiersFreeShippingTier[]門檻階層(依 amount 遞增,元件內會再排序一次並忽略非正數);未提供時以 threshold 建立單一「免運」階
thresholdnumber990單階簡寫:只有一個免運門檻時可直接給金額,等同 tiers=[{ amount, label: "免運" }];提供 tiers 時忽略
currencystring"NT$"幣別前綴,顯示在所有金額前
onTierReached(tier: FreeShippingTier, index: number) => void小計首次越過某一階時回呼;掛載當下已達成的階不會觸發,一次跨過多階會依序各觸發一次
compactbooleanfalse精簡模式:更薄的軌道、更小的文字,不顯示小計讀數、獎勵說明與 chip 列,適合貼在購物車頂欄
ariaLabelstring"免運門檻進度"進度條的無障礙標籤
classNamestring透傳到最外層容器

FreeShippingTier

欄位型別預設值說明
amountnumber門檻金額(小計達到含此金額即視為達成)
labelstring階層名稱,會出現在文案與 chip 上,例如「免運」「贈品」「折扣」
iconLucideIcon節點圖示;未提供時依序使用卡車/禮物/折扣標籤/星芒
rewardstring達標獎勵說明;顯示在下一階文案下方,並作為 chip 的 title

另外具名匯出 tierProgress(subtotal, tiers)(回傳 0–100 的軌道百分比)與 FreeShippingTier 型別,方便在別處畫同一套進度。

細節

  • 等寬分段:軌道百分比不是按金額比例,而是每一階佔相同寬度、階內線性內插。門檻金額往往差距懸殊(990 / 1500 / 3000),按比例畫會讓前段擠在一起、節點重疊;等寬讓版面穩定也更好讀
  • 差額無條件進位:「再買 NT$X」以 Math.ceil 計算,確保照著文案買一定跨得過門檻;金額一律以整數加千分位顯示
  • 顏色跟著最高達成階走:未達任何階時填色條為中性深色,達成第一階起依序切換翡翠綠 → 紫 → 琥珀 → 天藍(超過四階循環),chip 與節點各自沿用自己那一階的顏色
  • 彩帶只在「越過」時噴:以掛載當下的達成階數為基準,初始就已達成的階不噴、也不觸發 onTierReached;粒子軌跡是確定性表格,不用 Math.random,SSR 與 CSR 輸出一致
  • tiers 會在元件內濾掉非正數金額並依 amount 排序,因此傳入順序錯了也不會壞,但仍建議依遞增順序撰寫以免和 onTierReachedindex 對不上

可及性

  • 軌道使用 role="progressbar"aria-valuemin 為 0、aria-valuemax 為最高階金額、aria-valuenow 為目前小計,aria-valuetext 為完整文案(「小計 NT$640,再買 NT$350 即可享免運」)
  • 視覺上的滾動數字捲軸包含 0–9 全部字元,因此整段文案以 aria-hidden 隱藏,真正的訊息放在 role="status"aria-live="polite" 的隱藏段落,小計變動時螢幕閱讀器會朗讀最新差額
  • chip 列為語意化的 ul,每個 chip 附有「(已達成)/(未達成)」的隱藏文字;節點 title 提供階層名稱與門檻金額
  • 使用者系統開啟「減少動態效果」時:不噴彩帶、填色條與數字直接跳到定位、節點與 chip 不彈跳,僅保留顏色與文字變化

本頁目錄