WebberUI

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.jsonfiles[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滑掉一張卡時觸發
emptyStateReactNode預設提示全部滑完後顯示的內容
thresholdnumber100觸發飛出的水平位移閾值(px)
velocityThresholdnumber500觸發飛出的甩動速度閾值(px/s)
classNamestring堆疊容器樣式(通常在此指定高度)

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,只有最上層可互動。
  • 使用者系統開啟「減少動態效果」時,停用拖曳與旋轉,改以按鈕/鍵盤觸發淡出切換。

On this page