Docs
Animated Tooltip
A cool tooltip that reveals on hover, follows mouse pointer
Installation
Install dependencies
npm i motion clsx tailwind-merge
Add util file
lib/utils.ts
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Run the following command
It will create a new file animated-tooltip.tsx
inside the components/mage-ui/icon
directory.
mkdir -p components/mage-ui/icon && touch components/mage-ui/icon/animated-tooltip.tsx
Paste the code
Open the newly created file and paste the following code:
"use client";
import Image from "next/image";
import React, { useState } from "react";
import {
motion,
useTransform,
AnimatePresence,
useMotionValue,
useSpring,
} from "framer-motion";
type Person = {
id: number;
name: string;
designation: string;
image: string;
};
const AnimatedTooltip = ({
items,
}: {
items: Person[];
}) => {
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
const springConfig = { stiffness: 100, damping: 5 };
const x = useMotionValue(0);
const rotate = useSpring(useTransform(x, [-100, 100], [-45, 45]), springConfig);
const translateX = useSpring(useTransform(x, [-100, 100], [-50, 50]), springConfig);
const handleMouseMove = (event: React.MouseEvent<HTMLImageElement>) => {
const halfWidth = event.currentTarget.offsetWidth / 2;
x.set(event.nativeEvent.offsetX - halfWidth);
};
return (
<>
{items.map((item) => (
<div
className="-mr-4 relative group h-1/2"
key={item.id}
onMouseEnter={() => setHoveredIndex(item.id)}
onMouseLeave={() => setHoveredIndex(null)}
>
<AnimatePresence mode="popLayout">
{hoveredIndex === item.id && (
<motion.div
initial={{ opacity: 0, y: 20, scale: 0.6 }}
animate={{
opacity: 1,
y: 0,
scale: 1,
transition: { type: "spring", stiffness: 260, damping: 10 },
}}
exit={{ opacity: 0, y: 20, scale: 0.6 }}
style={{ translateX, rotate, whiteSpace: "nowrap" }}
className="absolute -top-16 -left-1/2 translate-x-1/2 flex text-xs flex-col items-center justify-center rounded-md bg-black z-50 shadow-xl px-4 py-2"
>
<div className="absolute inset-x-10 z-30 w-[20%] -bottom-px bg-gradient-to-r from-transparent via-emerald-500 to-transparent h-px" />
<div className="absolute left-10 w-[40%] z-30 -bottom-px bg-gradient-to-r from-transparent via-sky-500 to-transparent h-px" />
<div className="font-bold text-white relative z-30 text-base">
{item.name}
</div>
<div className="text-white text-xs">{item.designation}</div>
</motion.div>
)}
</AnimatePresence>
<Image
onMouseMove={handleMouseMove}
height={100}
width={100}
src={item.image}
alt={item.name}
className="object-cover !m-0 !p-0 object-top rounded-full h-14 w-14 border-2 group-hover:scale-105 group-hover:z-30 border-white relative transition duration-500"
/>
</div>
))}
</>
);
};
export default function AnimatedTooltipPage() {
const people: Person[] = [
{ id: 1, name: "John Doe", designation: "Software Engineer", image: "https://images.unsplash.com/photo-1599566150163-29194dcaad36?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3387&q=80" },
{ id: 2, name: "Robert Johnson", designation: "Product Manager", image: "https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Mnx8YXZhdGFyfGVufDB8fDB8fHww&auto=format&fit=crop&w=800&q=60" },
{ id: 3, name: "Jane Smith", designation: "Data Scientist", image: "https://images.unsplash.com/photo-1580489944761-15a19d654956?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8NXx8YXZhdGFyfGVufDB8fDB8fHww&auto=format&fit=crop&w=800&q=60" },
{ id: 4, name: "Emily Davis", designation: "UX Designer", image: "https://images.unsplash.com/photo-1438761681033-6461ffad8d80?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTB8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D&auto=format&fit=crop&w=800&q=60" },
{ id: 5, name: "Tyler Durden", designation: "Soap Developer", image: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3540&q=80" },
{ id: 6, name: "Dora", designation: "The Explorer", image: "https://images.unsplash.com/photo-1544725176-7c40e5a71c5e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3534&q=80" },
];
return (
<div className="flex flex-row items-center justify-center h-screen w-full">
<AnimatedTooltip items={people} />
</div>
);
}