Swipe Card Carousel

Smooth swipping carousel animation

bossadi zenithbossadi zenithbossadi zenithbossadi zenithbossadi zenith

Installation

Run the following command

It will create a new file one.tsx inside the components/carousel/one.tsx directory.

mkdir -p components/carousel && touch components/carousel/carousel.tsx

Paste the code

Open the newly created file and paste the following code:

"use client";
 
import { motion, useMotionValue, useTransform } from "framer-motion";
import { Dispatch, SetStateAction, useState } from "react";
 
type Card = {
  id: number;
  image: string;
};
 
const cardsData: Card[] = [
  {
    id: 1,
    image: "/others/photo-1.jpg",
  },
  {
    id: 2,
    image: "/others/photo-2.jpg",
  },
  {
    id: 3,
    image: "/others/photo-3.jpg",
  },
  {
    id: 4,
    image: "/others/photo-4.jpg",
  },
  {
    id: 5,
    image: "/others/photo-5.jpg",
  },
];
 
const Swipe = () => {
  const [cards, setCards] = useState<Card[]>(cardsData);
  return (
    <div className="h-full w-full grid place-items-center">
      {cards
        .slice()
        .reverse()
        .map((card, index) => (
          <Card
            key={card.id}
            item={card}
            cards={cards}
            setCards={setCards}
            index={index}
          />
        ))}
    </div>
  );
};
 
interface CardProps {
  cards: Card[];
  item: Card;
  setCards: Dispatch<SetStateAction<Card[]>>;
  index: number;
}
 
function Card({ item, cards, setCards, index }: CardProps) {
  const x = useMotionValue(0);
 
  const opacity = useTransform(x, [-160, 0, 160], [0, 1, 0]);
  const cardsRotation = useTransform(x, [-160, 160], [-20, 20]);
 
  const frontCard = index === 0;
 
  const rotate = useTransform(() => {
    const newOffset = frontCard ? 0 : index % 2 ? 10 : -10;
 
    return `${cardsRotation.get() + newOffset}deg`;
  });
 
  const handleDragEnd = () => {
    if (Math.abs(x.get()) > 50) {
      setCards((prevCards) => prevCards.filter((card) => card.id !== item.id));
    }
  };
 
  return (
    <motion.img
      src={item.image}
      drag={frontCard ? "x" : false}
      dragConstraints={{
        left: 0,
        right: 0,
      }}
      alt="bossadi zenith"
      className="h-96 origin-bottom border-4 w-80 rounded-2xl object-cover hover:cursor-grab active:cursor-grabbing"
      style={{
        opacity,
        rotate,
        x,
        transition: ".125s transform",
        gridRow: 1,
        gridColumn: 1,
        zIndex: cards.length - index,
      }}
      onDragEnd={handleDragEnd}
    />
  );
}
 
export default Swipe;

Credits

Built by Bossadi Zenith