Animated Video Tooltip using typescript and framer-motion

Video Tooltip is an animated component that activates when users hover over an avatar.

This component displays a short video of the person introducing themselves or providing additional context, adding a personal and interactive touch.

It’s particu…


This content originally appeared on DEV Community and was authored by Bro Karim

Video Tooltip is an animated component that activates when users hover over an avatar.

This component displays a short video of the person introducing themselves or providing additional context, adding a personal and interactive touch.

It's particularly useful for creating memorable user experiences, offering quick insights about team members, speakers, or influencers without requiring extra clicks.

Demo

// Detect dark theme var iframe = document.getElementById('tweet-1876277735032848773-256'); if (document.body.className.includes('dark-theme')) { iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1876277735032848773&theme=dark" }

Source Code

video-tooltip.tsx

import { useState, useCallback, useMemo } from "react";
import { motion, useTransform, AnimatePresence, useMotionValue, useSpring } from "framer-motion";
import { cn } from "@/lib/utils";

interface TooltipItem {
  id: number;
  name: string;
  designation: string;
  image: string;
  video: string;
  text: string;
}

interface VideoTooltipProps {
  items: TooltipItem[];
  className?: string;
}

export const VideoTooltip = ({ items, className = "" }: VideoTooltipProps) => {
  const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
  const [showText, setShowText] = useState(false);
  const springConfig = useMemo(
    () => ({
      stiffness: 100,
      damping: 5,
    }),
    []
  );

  // Motion setup
  const x = useMotionValue(0);
  const translateX = useSpring(useTransform(x, [-100, 100], [-50, 50]), springConfig);
  // Optimize event handler with useCallback
  const handleMouseMove = useCallback(
    (event: React.MouseEvent<HTMLElement>) => {
      const halfWidth = event.currentTarget.offsetWidth / 2;
      x.set(event.nativeEvent.offsetX - halfWidth);
    },
    [x]
  );

  return (
    <div className={cn("flex items-center gap-2", className)}>
      {items.map((item) => (
        <div className="-mr-4 relative group" key={item.name} 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: {
                    stiffness: 260,
                    damping: 10,
                    duration: 0.3,
                  },
                  width: showText ? "300px" : "96px",
                  height: showText ? "auto" : "96px",
                }}
                exit={{ opacity: 0, y: 20, scale: 0.6 }}
                style={{
                  translateX: translateX,
                  // rotate: rotate,
                  // whiteSpace: "nowrap",
                }}
                className="absolute w-24 h-24 group  -top-28 -left-1/2 translate-x-1/2 border-2 border-white flex text-xs flex-col bg-white items-center justify-center rounded-md  z-50 shadow-xl px-4 py-2"
              >
                <motion.div animate={{ opacity: showText ? 0 : 1 }} transition={{ duration: 0.3 }} className="absolute inset-0 z-10">
                  <video src={item.video} autoPlay muted loop playsInline className="w-full h-full object-cover rounded-md ring-black" />
                </motion.div>
                <motion.div className="p-1 w-full bg-white max-h-32 overflow-y-auto flex  flex-col" initial={{ opacity: 0 }} animate={{ opacity: showText ? 1 : 0 }} transition={{ duration: 0.3 }}>
                  <p className="text-sm text-black text-foreground-foreground">{item.text}</p>
                </motion.div>
                <div className=" relative h-full w-full ">
                  <div className={`absolute ${showText ? "left-0" : "-left-[16%]"} bottom-2 flex space-x-2 z-30 items-center justify-center rounded-full border border-white text-black p-1`}>
                    <button className={`text-[8px] h-auto rounded-full px-1 ${!showText ? "bg-black text-white" : ""}`} onClick={() => setShowText(false)}>
                      Video
                    </button>
                    <button className={`text-[8px] h-auto rounded-full px-1 ${showText ? "bg-black text-white" : ""}`} onClick={() => setShowText(true)}>
                      Text
                    </button>
                  </div>
                </div>
              </motion.div>
            )}
          </AnimatePresence>
          <img
            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-background relative transition duration-500"
          />
        </div>
      ))}
    </div>
  );
};


This content originally appeared on DEV Community and was authored by Bro Karim


Print Share Comment Cite Upload Translate Updates
APA

Bro Karim | Sciencx (2025-01-06T14:38:07+00:00) Animated Video Tooltip using typescript and framer-motion. Retrieved from https://www.scien.cx/2025/01/06/animated-video-tooltip-using-typescript-and-framer-motion/

MLA
" » Animated Video Tooltip using typescript and framer-motion." Bro Karim | Sciencx - Monday January 6, 2025, https://www.scien.cx/2025/01/06/animated-video-tooltip-using-typescript-and-framer-motion/
HARVARD
Bro Karim | Sciencx Monday January 6, 2025 » Animated Video Tooltip using typescript and framer-motion., viewed ,<https://www.scien.cx/2025/01/06/animated-video-tooltip-using-typescript-and-framer-motion/>
VANCOUVER
Bro Karim | Sciencx - » Animated Video Tooltip using typescript and framer-motion. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/01/06/animated-video-tooltip-using-typescript-and-framer-motion/
CHICAGO
" » Animated Video Tooltip using typescript and framer-motion." Bro Karim | Sciencx - Accessed . https://www.scien.cx/2025/01/06/animated-video-tooltip-using-typescript-and-framer-motion/
IEEE
" » Animated Video Tooltip using typescript and framer-motion." Bro Karim | Sciencx [Online]. Available: https://www.scien.cx/2025/01/06/animated-video-tooltip-using-typescript-and-framer-motion/. [Accessed: ]
rf:citation
» Animated Video Tooltip using typescript and framer-motion | Bro Karim | Sciencx | https://www.scien.cx/2025/01/06/animated-video-tooltip-using-typescript-and-framer-motion/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.