電商購物體驗

Bundle Builder

組合搭售機:點選商品縮圖以 FLIP 飛入插槽,總價滾動更新,集滿指定件數即填滿折扣環並解鎖折扣。

這是 WebberUI Pro 元件

下方的安裝指令需要授權才能執行,未授權時會回 401。

怎麼安裝 Pro 元件 →查看方案 →

把這個效果裝進你的專案

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

npx webberui@latest add "https://webberui.com/r/bundle-builder.json?t=<安裝 token>"

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

Playground

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

3
3
0.2
0
編輯中的呼叫預設屬性
<BundleBuilder/>

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

安裝

npx webberui@latest add "https://webberui.com/r/bundle-builder.json?t=<安裝 token>"

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

使用

import {
  BundleBuilder,
  type BundleProduct,
} from "@/components/ui/bundle-builder";

const products: BundleProduct[] = [
  { id: "a", name: "可頌", price: 65, thumbnail: "🥐" },
  { id: "b", name: "拿鐵", price: 120, thumbnail: "☕" },
  { id: "c", name: "沙拉", price: 150, thumbnail: "🥗" },
  { id: "d", name: "蛋糕", price: 95, thumbnail: "🍰" },
];

<BundleBuilder
  products={products}
  columns={4}
  slots={3}
  discount={0.2}
  currency="NT$"
  onAddToBundle={(items, total) => console.log(items, total)}
/>;

點選上方商品縮圖,縮圖會以 FLIP 動畫飛入下方插槽,插槽集滿設定的件數時,折扣環填滿並彈出折扣標籤、總價滾動至折後價。再次點選商品或插槽即可移除。

受控模式

傳入 selectedIds 即進入受控模式,改由外部狀態主導選取內容:

const [ids, setIds] = React.useState<string[]>([]);

<BundleBuilder
  products={products}
  selectedIds={ids}
  onSelectionChange={setIds}
  onUnlock={() => console.log("折扣已解鎖")}
/>;

Props

Prop型別預設值說明
productsBundleProduct[]—商品格要顯示的商品清單
slotsnumber3需集滿的插槽數,達成後解鎖折扣
columnsnumber3商品格欄數
discountnumber0.2集滿後套用的折扣比例(0–1)
currencystring"$"貨幣符號
localestring"en-US"數字千分位所用地區設定
decimalsnumber0價格顯示小數位數
selectedIdsstring[]—受控:目前選取的商品 id(依加入順序)
defaultSelectedIdsstring[]—非受控模式的初始選取
onSelectionChange(ids: string[]) => void—選取變更時觸發
onUnlock() => void—由未集滿轉為集滿、折扣解鎖時觸發一次
onAddToBundle(products, total) => void—點擊主要按鈕時觸發,回傳選取商品與折後總價
actionLabelReact.ReactNode"加入組合"主要按鈕文字
classNamestring—外層容器樣式

BundleProduct

欄位型別說明
idstring唯一識別碼,用於受控與 FLIP 對應
namestring商品名稱
pricenumber單價(未折扣)
thumbnailReact.ReactNode縮圖內容,可放 emoji、圖示或任意節點
thumbnailClassNamestring覆寫縮圖背景(Tailwind class)

細節

  • FLIP 飛入:以 Motion 的 layoutId 共享版面動畫實作。選取後同一縮圖從商品格移到插槽,Motion 自動量測前後位置做 FLIP 過場;格內留下打勾佔位以維持版面穩定。
  • 滾動總價:以 useMotionValue + animate 平滑滾動到新價,逐格更新不觸發 React re-render;集滿時套用折扣並顯示刪除線原價與省下金額。
  • 折扣環:SVG 環形進度隨集滿件數填滿;達標時環轉為強調色並彈出打勾與折扣百分比。
  • 插槽已滿時,未選取的商品會停用;點選插槽或已選商品即可移除。

可及性

  • 商品為原生 button,帶 aria-pressed 標示選取狀態,aria-label 含名稱與價格。
  • 插槽移除鍵帶「從組合移除 ⋯」的 aria-label;折扣環為裝飾性內容並標記 aria-hidden。
  • 選取進度與解鎖狀態透過 role="status" 的 aria-live 區域即時播報。
  • 使用者系統開啟「減少動態效果」時,FLIP、滾動數字與折扣環改為瞬間定位,不做過場動畫。