React swipe cards & stack — Tinder-style deck, physics animations, video, custom render. Touch-ready, TypeScript.
npm install react-cards-pro




Fluid, physics-based React swipe cards and stack — Tinder-style deck, FAANG-quality animations, video support, and custom render. Touch-optimized for mobile and tablet.
https://react-cards-pro.vercel.app
- Swipe cards — Tinder-style left/right swipe with physics (framer-motion + @use-gesture)
- Image, video & custom — Use image/video or renderCard for fully custom React components
- Endless mode — Loop the deck; swiped cards recycle to the end
- Auto-swipe — Optional slideshow; pauses on hover/touch
- Mobile-first — Touch-friendly, no native drag steal, responsive
- TypeScript — Full types, CardItem + ReactCardsProProps exported
``bash`
npm i react-cards-pro
`tsx
import { ReactCardsPro } from 'react-cards-pro';
const data = [
{ id: '1', image: '/photo.jpg', title: 'Card 1' },
{ id: '2', image: '/photo2.jpg', video: '/video.mp4', title: 'Card 2' },
];
messyStack
onSwipe={(direction, item) => console.log(direction, item)}
/>
`
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| data | CardItem[] | — | Array of cards: { id, image?, video?, title? }. image optional when using renderCard. |stackDepth
| | number | 3 | Max cards in DOM (active + next N−1). |scaleRatio
| | number | 0.05 | Scale step between stacked cards. |yOffset
| | number | -10 | Vertical offset (px) per stack level. |cardMaxWidth
| | number | 380 | Max width (px) of the card stack. |messyStack
| | boolean | true | Random rotation on background cards. |scatterRandomness
| | number | 5 | Max scatter rotation (deg). |animateRotation
| | boolean | true | Map drag to rotation. |animateScale
| | boolean | true | Map drag to scale. |swipeThreshold
| | number | 150 | Min drag (px) to trigger swipe. |maxRotation
| | number | 15 | Max rotation (deg) at threshold. |endless
| | boolean | false | When true, swiped cards move to the end so the deck never empties. |autoSwipe
| | boolean | false | Enable slideshow-style auto-swipe. |autoSwipeDirection
| | 'alternating' \| 'right' \| 'left' | 'alternating' | Direction for auto-swipe. |autoSwipeInterval
| | number | 4000 | Interval (ms) between auto-swipes. |disableAudioControls
| | boolean | false | Hide custom mute/volume overlay on video cards. |hideMuteButton
| | boolean | false | When true, hides the mute button on video cards. |initialMuted
| | boolean | true | Videos start muted. |onSwipe
| | (direction: string, item: CardItem) => void | — | Called when a card is swiped. |onClick
| | (item: CardItem) => void | — | Called when the active card is clicked/tapped (minimal drag, no swipe). |renderCard
| | (item, { depth, isActive }) => ReactNode | — | Custom render for each card. Overrides image/video when provided. |
Use renderCard to render your own React component instead of image/video:
` {item.description}tsx`
renderCard={(item, { depth, isActive }) => (
{item.title}
{isActive && Active}
)}
onSwipe={(dir, item) => console.log(dir, item)}
/>
renderCard receives the CardItem and { depth, isActive }. Your component is wrapped in the same card chrome (border-radius, shadow, gestures).
`tsx`
endless
onSwipe={(dir, item) => console.log('Swiped', dir, item.title)}
/>
With endless={true}, each swiped card is moved to the back of the list so the stack loops forever.
- Gestures use touch-friendly defaults and pointer capture.
- Images and videos are non-draggable so the browser doesn’t steal drags.
- The stack uses touch-action: none and responsive layout (width: 100%, aspectRatio: 3/4, maxWidth: 380`).
- Live demo: react-cards-pro.vercel.app
- npm: react-cards-pro on npm
- Author: Don Sirivat (LinkedIn)
MIT