Swipe Cards
Tinder 式滑卡堆疊,可拖曳、依速度飛出,並提供程式化左右滑與空狀態。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
100
500
<SwipeCards />
安裝
npx shadcn@latest add https://webberui.com/r/swipe-cards.json或在 components.json 設定 registries 後,改用 @webberui/swipe-cards 安裝。
安裝依賴後,從 registry JSON(/r/swipe-cards.json 的 files[0].content)複製 swipe-cards.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion lucide-react clsx tailwind-merge使用
import * as React from "react";
import {
SwipeCards,
type SwipeCardsHandle,
} from "@/components/ui/swipe-cards";
const ref = React.useRef<SwipeCardsHandle>(null);
<SwipeCards
ref={ref}
cards={[
{ id: 1, content: <div className="h-52 rounded-2xl bg-sky-500" /> },
{ id: 2, content: <div className="h-52 rounded-2xl bg-rose-500" /> },
]}
onSwipe={(id, dir) => console.log(id, dir)}
className="h-60 w-72"
/>;
// 程式化左右滑
<button onClick={() => ref.current?.swipe("left")}>略過</button>
<button onClick={() => ref.current?.swipe("right")}>喜歡</button>最上層卡片可用滑鼠或觸控往左右拖曳,x 位移會即時映射成旋轉角度與「喜歡/略過」提示;放開時若位移超過 threshold 或甩動速度超過 velocityThreshold,卡片會朝該方向飛出並露出下一張。全部滑完後顯示 emptyState。
Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
cards | { id: string | number; content: ReactNode }[] | — | 卡片陣列,第一項在最上層 |
onSwipe | (id, dir: "left" | "right") => void | — | 滑掉一張卡時觸發 |
emptyState | ReactNode | 預設提示 | 全部滑完後顯示的內容 |
threshold | number | 100 | 觸發飛出的水平位移閾值(px) |
velocityThreshold | number | 500 | 觸發飛出的甩動速度閾值(px/s) |
className | string | — | 堆疊容器樣式(通常在此指定高度) |
Ref(SwipeCardsHandle)
| 方法 | 型別 | 說明 |
|---|---|---|
swipe | (dir: "left" | "right") => void | 以程式方式滑掉最上層卡片,可用於自訂按鈕 |
細節
- 後方卡片依深度逐層縮小並下移,露出邊緣形成堆疊感;同時最多渲染 3 層。
- 拖曳採
drag="x",useTransform將位移映射為旋轉角度;飛出使用 spring,離場後才更新索引並讓下一張補位。 - 容器高度建議透過
className指定(例如h-60),卡片內容自行決定寬高;容器不裁切,飛出的卡片才能完整離場。
可及性
- 最上層卡片可聚焦(
tabIndex=0),支援 → 喜歡、← 略過,並帶有role="group"與操作說明的aria-label。 - 後方卡片以
aria-hidden對輔助科技隱藏,且pointer-events: none,只有最上層可互動。 - 使用者系統開啟「減少動態效果」時,停用拖曳與旋轉,改以按鈕/鍵盤觸發淡出切換。