Animated Tooltip
A cool tooltip that reveals on hover, follows mouse pointer.
Installation
Install the following dependencies
bash
pnpm add motion-vCopy and paste the following code into your project:
vue
<script setup lang="ts">
import { AnimatePresence, motion, useMotionValue, useSpring, useTransform } from "motion-v";
import { ref } from "vue";
export interface Items {
id: number;
name: string;
designation: string;
image: string;
}
const props = defineProps<{
items: Items[];
}>();
const hoveredIndex = ref<number | null>(null);
const springConfig = { stiffness: 100, damping: 5 };
const x = useMotionValue(0);
const rotate = useSpring(useTransform(x, [-100, 100], [-45, 45]), springConfig);
// translate the tooltip
const translateX = useSpring(useTransform(x, [-100, 100], [-50, 50]), springConfig);
function handleMouseMove(event: any) {
const halfWidth = event.target.offsetWidth / 2;
x.set(event.offsetX - halfWidth);
}
</script>
<template>
<div v-for="(item, idx) in props.items" :key="idx">
<div
:key="item.name"
class="group relative -mr-4"
@mouseenter="() => (hoveredIndex = item.id)"
@mouseleave="() => (hoveredIndex = null)"
>
<AnimatePresence mode="popLayout">
<div v-if="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',
}"
class="absolute -top-16 -left-1/2 z-50 flex -translate-x-1/2 flex-col items-center justify-center rounded-md bg-black px-4 py-2 text-xs shadow-xl"
>
<div
class="absolute inset-x-10 -bottom-px z-30 h-px w-[20%] bg-gradient-to-r from-transparent via-emerald-500 to-transparent"
/>
<div
class="absolute -bottom-px left-10 z-30 h-px w-[40%] bg-gradient-to-r from-transparent via-sky-500 to-transparent"
/>
<div class="relative z-30 text-base font-bold text-white">
{{ item.name }}
</div>
<div class="text-xs text-white">
{{ item.designation }}
</div>
</motion.div>
</div>
</AnimatePresence>
<img
:src="item.image"
:alt="item.name"
height="100"
width="100"
class="relative !m-0 h-14 w-14 rounded-full border-2 border-white object-cover object-top !p-0 transition duration-500 group-hover:z-30 group-hover:scale-105"
@mousemove="handleMouseMove"
/>
</div>
</div>
</template>Props
| Prop | Type | Description | Default |
|---|---|---|---|
| items | Array<{id: number, name: string, designation: string, image: string}> | An array of objects, each representing an item. Each object in the array should have the following properties: id, name, designation, image. | - |