Cards
Interactive Book
#card#book#flip#3d
The Design of UI
The Design of UI
John Doe
implementedInfinityUI component
This component is fully implemented in InfinityUI and wired into the docs and registry flow.
Installation
Use the registry command to add the component source, and install any package dependencies if needed.
Infinity Registry
Install the component source into your project with the shadcn CLI.
npx shadcn@latest add https://infinityui-pearl.vercel.app/r/interactive-bookPackage Dependencies
Install the npm packages used by this component source.
npm install framer-motionComponent Code
Copy and paste this code into your component file.
tsx
"use client";
import { useState } from "react";
import { motion } from "framer-motion";
interface InteractiveBookProps {
title: string;
author: string;
coverColor?: string;
spineColor?: string;
pagesColor?: string;
children?: React.ReactNode;
}
export function InteractiveBook({
title,
author,
coverColor = "bg-zinc-800",
spineColor = "bg-zinc-900",
pagesColor = "bg-zinc-200",
children
}: InteractiveBookProps) {
const [isHovered, setIsHovered] = useState(false);
return (
<div
className="relative w-48 h-64 md:w-56 md:h-72 cursor-pointer [perspective:1000px] group"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<motion.div
className="w-full h-full relative [transform-style:preserve-3d] transition-transform duration-700 ease-out"
animate={{
rotateY: isHovered ? -25 : -15,
rotateX: isHovered ? 10 : 0,
z: isHovered ? 50 : 0,
scale: isHovered ? 1.05 : 1
}}
>
{/* Book Spine */}
<div
className={`absolute inset-y-0 left-0 w-8 ${spineColor} origin-right border-l border-white/10 flex flex-col items-center py-6 shadow-[-10px_0_20px_rgba(0,0,0,0.5)]`}
style={{ transform: "rotateY(-90deg) translateZ(16px)" }}
>
<span className="text-white/40 text-[10px] font-medium tracking-widest writing-mode-vertical uppercase transform rotate-180">
{title}
</span>
</div>
{/* Book Pages (Right Side) */}
<div
className={`absolute inset-y-1 right-0 w-8 ${pagesColor} origin-left flex flex-col justify-evenly py-2 px-1 rounded-r shadow-inner`}
style={{ transform: "rotateY(90deg) translateZ(112px)" }}
>
<div className="w-full h-[1px] bg-zinc-400/30"></div>
<div className="w-full h-[1px] bg-zinc-400/30"></div>
<div className="w-full h-[1px] bg-zinc-400/30"></div>
<div className="w-full h-[1px] bg-zinc-400/30"></div>
<div className="w-full h-[1px] bg-zinc-400/30"></div>
</div>
{/* Book Pages (Top) */}
<div
className={`absolute top-0 inset-x-0 h-8 ${pagesColor} origin-bottom rounded-t`}
style={{ transform: "rotateX(90deg) translateZ(144px)" }}
/>
{/* Book Pages (Bottom) */}
<div
className={`absolute bottom-0 inset-x-0 h-8 ${pagesColor} origin-top rounded-b`}
style={{ transform: "rotateX(-90deg) translateZ(144px)" }}
/>
{/* Front Cover */}
<div
className={`absolute inset-0 ${coverColor} rounded-r-xl border-l-4 border-black/20 shadow-2xl overflow-hidden`}
style={{ transform: "translateZ(16px)" }}
>
{/* Cover Inner Shadow/Highlight */}
<div className="absolute inset-0 bg-gradient-to-r from-black/40 via-transparent to-white/5 pointer-events-none"></div>
{children ? (
<div className="relative z-10 w-full h-full">{children}</div>
) : (
<div className="relative z-10 p-6 h-full flex flex-col items-center justify-center text-center gap-4">
<h3 className="text-xl md:text-2xl font-bold tracking-tighter text-white leading-tight">
{title}
</h3>
<div className="w-8 h-px bg-white/20"></div>
<p className="text-xs text-zinc-400 uppercase tracking-widest font-medium">
{author}
</p>
</div>
)}
</div>
{/* Back Cover */}
<div
className={`absolute inset-0 ${coverColor} rounded-l-xl`}
style={{ transform: "rotateY(180deg) translateZ(16px)" }}
/>
</motion.div>
</div>
);
}