Circle Menu
NewDialog Form
NewFlip Scroll
NewHorizontal Scroll
NewImage Pile
Interactive CTA
NewInteractive Folder
NewInterest Picker
NewJelly Loader
Mask Cursor Effect
Magnet Tabs
Masonry Grid
OTP Input
NewPhoto Gallery
NewPixelated Carousel
NewRubik Cube
NewSine Wave
NewSkeumorphic Music Card
Stacked Input Form
NewStack Scroll
NewTrading Card
Trading Card
A card that moves in 3D when you hover over it. Perfect for showcasing profiles, characters, or products with engaging effects.
Install dependencies
npm i framer-motion tailwindcss
Component
Create a file trading-card.tsx in your components folder and paste this code
import { motion, useAnimationControls } from 'framer-motion';
import Image from 'next/image';
import React, { useRef } from 'react';
interface TradingCardProps {
imageUrl: string;
rank: number;
name: string;
description: string;
}
const TradingCard: React.FC<TradingCardProps> = ({ imageUrl, rank, name, description }) => {
const cardRef = useRef<HTMLDivElement>(null);
const backgroundControls = useAnimationControls();
const contentControls = useAnimationControls();
const cardControls = useAnimationControls();
const onMouseEnter: React.MouseEventHandler<HTMLDivElement> = () => {
contentControls.start({ x: -300 });
backgroundControls.start({ scale: 1.05, opacity: 1 });
};
const onMouseLeave = () => {
contentControls.start({ x: 0, transition: { delay: 0.5 } });
backgroundControls.start({ scale: 0.95, opacity: 0.4 });
cardControls.start({ transform: `rotateY(0deg) rotateX(0deg)` });
};
const onMouseMove: React.MouseEventHandler<HTMLDivElement> = (e) => {
if (!cardRef.current) return;
const rect = cardRef.current?.getBoundingClientRect();
if (!rect) return;
const mx = e.clientX - rect.left;
const my = e.clientY - rect.top;
const width = rect.right - rect.left;
const height = rect.bottom - rect.top;
const xd = (mx - width / 2) / 10;
const yd = (height / 2 - my) / 10;
cardRef.current.style.transform = `perspective(1000px) rotateY(${xd}deg) rotateX(${yd}deg)`;
};
return (
<motion.div
ref={cardRef}
onMouseMove={onMouseMove}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
initial={{
transform: 'perspective(1000px) rotateX(0deg) rotateY(0deg)'
}}
style={{
transformStyle: 'preserve-3d'
}}
animate={cardControls}
className="flex flex-col hover:scale-105 transition-all duration-200 ease-linear items-start justify-end rounded-lg relative shadow-xl overflow-hidden h-[400px] w-[300px] cursor-pointer border-[1px] border-neutral-800"
>
<motion.div
className="h-full w-full absolute z-0"
initial={{
opacity: 0.4,
scale: 0.95
}}
animate={backgroundControls}
transition={{ duration: 0.7, ease: 'backOut' }}
>
<div className="h-full w-full inset-0 bg-cover bg-center">
<Image src={imageUrl} alt={name} fill className="object-cover" />
</div>
</motion.div>
<div className="font-semibold absolute top-5 right-5 z-10 text-white/70">#{rank}</div>
<motion.div
animate={contentControls}
transition={{ duration: 0.5, ease: 'backOut' }}
className="p-5 h-full w-full flex flex-col justify-end bg-transparent z-10 opacity-90"
>
<div className="font-medium">
{name.split(' ').map((word) => {
return (
<div
key={word}
className="flex flex-col items-start justify-start text-4xl font-bold"
>
{word} <br />
</div>
);
})}
</div>
<p className="text-sm text-white/90">{description}</p>
</motion.div>
</motion.div>
);
};
export default TradingCard;
Usage
import TradingCard from './ui/trading-card';
const TradingCardDemo = () => {
const cards = [
{
imageUrl: 'https://ky008ymy6s.ufs.sh/f/NFGlOqM3XnMdo7u44DpEAkCcBT6MsuPK2yhGzx8aIU5obVlp',
rank: 7,
name: 'Neymar Jr',
description:
"Genius on the field, Neymar's journey is a testament to talent, resilience, and the pursuit of excellence. His electrifying skills and unwavering determination make him a force to be reckoned with."
},
{
imageUrl: 'https://ky008ymy6s.ufs.sh/f/NFGlOqM3XnMdZrkXcU6sM1fhWrqco2HGsiP6knYBUV47mRvA',
rank: 10,
name: 'Lionel Messi',
description:
"Unstoppable force, unrivaled skill - Messi's legacy is built on precision, perseverance, and a relentless drive to redefine greatness on the field."
},
{
imageUrl: 'https://ky008ymy6s.ufs.sh/f/NFGlOqM3XnMddKZzHaIWPBmp7t6OxSiRdMrTJ4l3g1KX0fqj',
rank: 7,
name: 'Cristiano Ronaldo',
description:
"Legendary striker, Ronaldo's career is a testament to relentless ambition, unmatched talent, and a relentless pursuit of excellence. His journey is a story of resilience, determination, and a relentless drive to redefine greatness on the field."
}
];
return (
<div className="h-[700px] flex flex-col items-start justify-start lg:items-center lg:justify-center w-full gap-6">
<p className="md:text-2xl font-bold w-full text-center lg:mt-0 mt-10 ">
The greatest to have ever played
</p>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:flex lg:flex-row w-full items-center justify-center gap-6">
{cards.map((card, index) => (
<div className="w-full lg:w-fit flex items-center justify-center">
<TradingCard key={index} {...card} />
</div>
))}
</div>
</div>
);
};
export default TradingCardDemo;