Page through profiles, testimonials, or onboarding screens by throwing cards. Drag the top card and it rotates with the throw and tints toward your intent. Release past the threshold and it flies off while the next card springs forward. Drag, use the buttons, or press the arrow keys.
pnpm dlx shadcn@latest add "https://godui.design/r/lab/swipe-deck.json"
The front card is a draggable spring; its rotation is mapped from the drag
distance and the intent badges fade in as you pass a small offset. A release
past threshold (or a fast enough flick) dismisses it with momentum, and the
deck behind springs up a rank.
import { SwipeDeck } from "@/components/godui/swipe-deck";
<SwipeDeck onSwipe={(index, direction) => save(index, direction)}>
<Card>One</Card>
<Card>Two</Card>
<Card>Three</Card>
</SwipeDeck>
With loop, swiped cards are re-appended so the deck never empties. Use it for
testimonial reels.
<SwipeDeck loop>{/* cards */}</SwipeDeck>
<SwipeDeck actions={{ left: "Pass", right: "Connect" }}>{/* cards */}</SwipeDeck>
The deck is a focusable group: ← and → swipe, and the
labelled buttons below do the same. When prefers-reduced-motion is set, the
spring settling is removed.
| Prop | Type | Default | Description |
|---|
onSwipe | (index: number, dir: SwipeDirection) => void | none | Fired when the front card is swiped away. |
loop | boolean | false | Re-append swiped cards so the deck never empties. |
threshold | number | 110 | Drag distance (px) past which a release dismisses. |
actions | { left: string; right: string } | none | Labels for the left/right actions and intent badges. |
SwipeDeck also forwards every standard <div> attribute to the root element.