ComponentsCard Hover Effect
Card Hover Effect
Luxe
Explore the new library of components copy and paste.
Luxe
Explore the new library of components copy and paste.
Luxe
Explore the new library of components copy and paste.
Terminal
npm i framer-motion clsx tailwind-merge
utils/cn.ts
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
CardHoverEffect.tsx
"use client"; // @NOTE: add in case you are using Next.js
import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { cn } from "@/utils/cn";
type CardHoverEffectProps = {
containerClassName?: string;
className?: string;
hoveredItemClassName?: string;
} & React.ComponentProps<"div">;
export function CardHoverEffect({
containerClassName,
className,
hoveredItemClassName,
}: CardHoverEffectProps) {
const [hoveredIdx, setHoveredIdx] = useState<number | null>(null);
const ITEMS = [
{
title: "Luxe",
description: "Explore the new library of components copy and paste.",
},
{
title: "Luxe",
description: "Explore the new library of components copy and paste.",
},
{
title: "Luxe",
description: "Explore the new library of components copy and paste.",
},
];
return (
<div className={cn("grid md:grid-cols-3", containerClassName)}>
{ITEMS.map(({ title, description }, idx) => (
<div
key={idx}
className={cn("relative flex flex-col gap-3 p-4", className)}
onMouseEnter={() => setHoveredIdx(idx)}
onMouseLeave={() => setHoveredIdx(null)}
>
<AnimatePresence>
{hoveredIdx === idx && (
<motion.span
className={cn(
"absolute inset-0 z-0 block h-full w-full rounded-xl bg-neutral-900",
hoveredItemClassName,
)}
layoutId="cardHoverEffect"
initial={{ opacity: 0 }}
animate={{
opacity: 1,
transition: { duration: 0.15 },
}}
exit={{
opacity: 0,
transition: { duration: 0.15, delay: 0.2 },
}}
/>
)}
</AnimatePresence>
<div className="z-[1] select-none space-y-3">
<h1 className="font-medium text-white">{title}</h1>
<p className="text-neutral-400">{description}</p>
</div>
</div>
))}
</div>
);
}