A tactile way to page through profiles, testimonials, or onboarding screens. Drag the top card — 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 the arrow keys.
pnpm dlx shadcn@latest add "https://godui.design/r/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 — handy 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 | — | Fired when the front card is swiped away. |
loop | boolean | false | Re-append swiped cards so the deck never empties. |
threshold | number | 120 | Drag distance (px) past which a release dismisses. |
actions | { left: string; right: string } | — | Labels for the left/right actions and intent badges. |
SwipeDeck also forwards every standard <div> attribute to the root element.