堆疊窺視輪播
卡片堆疊後層窺視的輪播,滑動時後卡遞補上前。
當前卡片置中顯示,後方 2–3 張向上縮小偏移、露出可窺視的邊緣;拖曳或按鈕切換時前卡帶旋轉飛出、後卡以 spring 遞補上前,支援首尾循環與圓點指示,適合行程卡、商品卡等精選內容瀏覽。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add stacked-peek-carouselStacked Peek Carousel 是用 React、Tailwind CSS 與 Motion 做的堆疊卡片輪播(stacked carousel)元件:後方卡片向上縮小、露出邊緣,拖曳或按按鈕時前卡帶旋轉飛出,後卡以 spring 遞補;左右箭頭圖示來自 lucide-react。
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
<StackedPeekCarousel/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
適用情境
- 旅遊、活動或課程的精選卡片,一次專注介紹一個項目。
- 電商首頁的推薦商品或新品區塊,行動版用拖曳切換。
- 作品集或客戶案例的精簡展示,空間有限時取代橫向列表。
- App 介紹頁的功能卡片,搭配下方說明文字同步切換。
- 不適合:需要自動播放與分段進度條時,改用 Vertical Story Carousel。
安裝
npx webberui@latest add https://webberui.com/r/stacked-peek-carousel.json或在 components.json 設定 registries 後,改用 @webberui/stacked-peek-carousel 安裝。
使用
import { StackedPeekCarousel } from "@/components/ui/stacked-peek-carousel";
<StackedPeekCarousel
items={[
<TripCard key="kyoto" title="京都・嵐山" />,
<TripCard key="swiss" title="瑞士・少女峰" />,
<TripCard key="palau" title="帛琉・洛克群島" />,
]}
peek={2}
onIndexChange={(index) => console.log("目前在第", index + 1, "張")}
/>每個 item 會鋪滿舞台區域(預設 h-72 w-64,可用 stageClassName 覆寫),建議卡片本身設定 h-full w-full 與圓角背景。
範例
商品推薦卡片
items 接受任意 ReactNode 陣列,每個節點都要有 key。用 stageClassName 調整卡片舞台尺寸,卡片本身設 h-full w-full。
import { StackedPeekCarousel } from "@/components/ui/stacked-peek-carousel";
const products = [
{ id: "kettle", name: "手沖細口壺", price: "NT$1,280", image: "/products/kettle.jpg" },
{ id: "grinder", name: "手搖磨豆機", price: "NT$2,450", image: "/products/grinder.jpg" },
{ id: "dripper", name: "陶瓷濾杯", price: "NT$680", image: "/products/dripper.jpg" },
];
<StackedPeekCarousel
stageClassName="h-96 w-72"
items={products.map((p) => (
<a
key={p.id}
href={`/products/${p.id}`}
className="flex h-full w-full flex-col overflow-hidden rounded-2xl border bg-white shadow-md"
>
<img src={p.image} alt="" className="h-3/4 w-full object-cover" draggable={false} />
<div className="p-4">
<p className="font-medium">{p.name}</p>
<p className="text-sm text-neutral-500">{p.price}</p>
</div>
</a>
))}
/>同步顯示說明文字
元件內部管理目前索引,透過 onIndexChange 把索引同步到外部狀態,就能在輪播下方顯示對應的說明。直接傳入 setIndex 可保持回呼參考穩定。
"use client";
import * as React from "react";
import { StackedPeekCarousel } from "@/components/ui/stacked-peek-carousel";
const features = [
{ id: "sync", title: "多裝置同步", body: "手機、平板與電腦的資料即時同步。" },
{ id: "share", title: "共用清單", body: "邀請家人一起編輯同一份清單。" },
{ id: "remind", title: "到點提醒", body: "抵達指定地點時自動跳出提醒。" },
];
export function FeatureTour() {
const [index, setIndex] = React.useState(0);
return (
<div className="space-y-4 text-center">
<StackedPeekCarousel
onIndexChange={setIndex}
items={features.map((f) => (
<div key={f.id} className="flex h-full w-full items-center justify-center rounded-2xl bg-neutral-900 text-lg text-white">
{f.title}
</div>
))}
/>
<p className="text-sm text-neutral-600">{features[index].body}</p>
</div>
);
}不循環、加深堆疊
loop={false} 時到最後一張就停止,箭頭會變成停用狀態;peek、offset 與 scaleStep 調整後方露出的層數、間距與縮小比例。
<StackedPeekCarousel
items={cards}
loop={false}
showDots={false}
peek={3}
offset={12}
scaleStep={0.05}
/>Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
items | React.ReactNode[] | — | 輪播卡片內容清單,每個節點鋪滿舞台區域 |
peek | number | 2 | 後方可窺視的堆疊層數 |
offset | number | 16 | 每層堆疊向上偏移的距離(px) |
scaleStep | number | 0.06 | 每層堆疊縮小的比例(0–1) |
loop | boolean | true | 是否首尾循環 |
showDots | boolean | true | 是否顯示圓點指示器 |
showArrows | boolean | true | 是否顯示左右切換按鈕 |
stageClassName | string | — | 舞台(卡片堆疊區)的尺寸樣式,預設 h-72 w-64 |
onIndexChange | (index: number) => void | — | 目前索引變更時的回呼 |
className | string | — | 透傳到最外層容器 |
可及性
- 舞台標記為
role="region"搭配aria-roledescription="carousel",並在標籤中標示總張數 - 目前位置以
aria-live="polite"區塊即時播報「第 X 張,共 N 張」 - 後方窺視卡片以
aria-hidden對輔助科技隱藏,並以pointer-events-none停用互動 - 左右按鈕與圓點皆為原生
button,可鍵盤聚焦與操作,各自附上「上一張/下一張/跳至第 N 張」的aria-label,當前圓點標記aria-current - 使用者系統開啟「減少動態效果」時停用拖曳手勢與彈簧動畫,切換改為即時完成
常見問題
可以在 Next.js App Router 使用嗎?
可以。元件檔案開頭已有 "use client",在 Server Component 頁面直接 import 即可。只是 items 是 React 節點陣列,傳 onIndexChange 這類函式時,外層要是 Client Component。
可以從外部指定目前顯示第幾張嗎?
不行。元件沒有 index 這類受控 prop,也沒有自動播放;目前索引由內部管理,外部只能透過 onIndexChange 得知變化。使用者可以拖曳、點左右按鈕或點圓點切換。
往右拖為什麼也是下一張?
拖曳的位移加上速度加權超過門檻時一律前進到下一張,拖曳方向只決定前卡往哪一側飛出。要回到上一張請用左箭頭或圓點。
鍵盤可以操作嗎?
左右按鈕與圓點都是原生 button,可用 Tab 聚焦並以 Enter/空白鍵操作;舞台本身沒有綁定方向鍵。系統開啟「減少動態效果」時會停用拖曳與彈簧動畫,改為即時切換。
需要哪些依賴?
依賴是 motion、lucide-react(箭頭圖示)、clsx 與 tailwind-merge。不用 CLI 的話,從安裝區塊的「手動」分頁複製原始碼即可。