Skip to content
Skip to Content
DocsTrading Card
Trading Card

Trading Card

A 3D interactive trading card with perspective transforms that respond to mouse movement. Features smooth reveal animations and a premium holographic feel.

Component preview

Install using CLI

npx shadcn@latest add "https://www.obsidianui.dev/r/trading-card.json"

Install Manually

1

Install dependencies

npm install motion
2

Copy the source code

Copy into components/block/trading-card.tsx

Code
import { motion, useAnimationControls } from 'motion/react'; 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 onMouseEnter = () => { 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 }); }; const onMouseMove: React.MouseEventHandler<HTMLDivElement> = (e) => { if (!cardRef.current) return; const rect = cardRef.current.getBoundingClientRect(); const mx = e.clientX - rect.left; const my = e.clientY - rect.top; const xd = (mx - rect.width / 2) / 10; const yd = (rect.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} className="flex flex-col hover:scale-105 transition-all items-start justify-end rounded-lg relative shadow-xl overflow-hidden h-[400px] w-[300px] cursor-pointer border 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' }} > <Image src={imageUrl} alt={name} fill className="object-cover" /> </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 flex flex-col justify-end z-10" > <div className="text-4xl font-bold">{name}</div> <p className="text-sm text-white/90">{description}</p> </motion.div> </motion.div> ); }; export default TradingCard;

Props

PropTypeDefaultDescription
imageUrlstring-URL of the card background image
ranknumber-Rank number displayed in corner
namestring-Name/title of the card
descriptionstring-Description text
Last updated on