WebberUI

Swipe Cards

A Tinder-style swipe card stack that can be dragged, flies out by velocity, and offers programmatic left/right swipes and an empty state.

Loading preview…
npx shadcn@latest add https://webberui.com/r/swipe-cards.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

100
500
<SwipeCards />

Installation

npx shadcn@latest add https://webberui.com/r/swipe-cards.json

Or, once registries are configured in components.json, install it as @webberui/swipe-cards.

Usage

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"
/>;

// Programmatic left/right swipes
<button onClick={() => ref.current?.swipe("left")}>Skip</button>
<button onClick={() => ref.current?.swipe("right")}>Like</button>

The topmost card can be dragged left or right with the mouse or by touch, and the x offset maps live to a rotation angle and a "like / skip" cue. On release, if the offset exceeds threshold or the flick velocity exceeds velocityThreshold, the card flies out in that direction and reveals the next one. Once everything has been swiped, emptyState is shown.

Props

PropTypeDefaultDescription
cards{ id: string | number; content: ReactNode }[]The array of cards; the first item sits on top
onSwipe(id, dir: "left" | "right") => voidFires when a card is swiped away
emptyStateReactNodedefault messageThe content shown once everything has been swiped
thresholdnumber100Horizontal offset threshold that triggers the fly-out (px)
velocityThresholdnumber500Flick velocity threshold that triggers the fly-out (px/s)
classNamestringStack container styling (usually where you set the height)

Ref (SwipeCardsHandle)

MethodTypeDescription
swipe(dir: "left" | "right") => voidProgrammatically swipes away the topmost card, useful for custom buttons

How it works

  • The cards behind shrink and shift down layer by layer with depth, exposing their edges to create the sense of a stack; at most 3 layers are rendered at once.
  • The drag uses drag="x", with useTransform mapping the offset to a rotation angle; the fly-out uses a spring, and the index only updates after the exit so the next card moves up.
  • Set the container height through className (h-60, say), and let the card content decide its own width and height; the container does not clip, so the flying card can exit completely.

Accessibility

  • The topmost card is focusable (tabIndex=0) and supports to like and to skip, carrying role="group" and an aria-label explaining the interaction.
  • The cards behind are hidden from assistive technology with aria-hidden and have pointer-events: none, so only the topmost one is interactive.
  • When the user has "reduce motion" enabled at the system level, the drag and the rotation are disabled, switching instead to a fade out triggered by button or keyboard.

On this page