Experiments

About

Back

Creating A Tooltip That Follows Your Mouse Position

July 2023

  • Javascript

  • React

A popup tooltip that follows your mouse position around. This could have a number of different applications - perhaps you want to display certain contextual information when hovering over specific elements within the container.

The implementation is pretty simple too. We just have a few different state variables to track if the container is being hovered, and then the x and y of the mouse position relative to the container. We pass these x and y values to the top and left CSS properties of an absolutely positioned tooltip element within the container. Add a small CSS translate to the tooltip to ensure it doesn' block the mouse view, in this case we place it slightly over the mouse position and read out the x and y values of the mouse position within the container.

Try hovering over the container:

Component Code:

const TooltipAreaComponent = () => {
  const [posX, setPosX] = useState(0);
  const [posY, setPosY] = useState(0);
  const [areaHovered, setAreaHovered] = useState(false);

  const handleMouseMove = (event: React.MouseEvent<HTMLDivElement>) => {

    // Get the mouse coordinates relative to the container
    // first, we get the container element's distance from the top and left edges of the viewport
    const { left, top } = event.currentTarget.getBoundingClientRect();

    // then we subtract that from the mouse event position to get the correct x and y coordinates relative to the container
    const mouseX = event.clientX - left;
    const mouseY = event.clientY - top;

    // Update the state with the current mouse coordinates
    setPosX(mouseX);
    setPosY(mouseY);
  };

  return (
    <div
      className="w-200 h-60 border border-dashed border-slate-400 bg-slate-100 relative"
      onMouseMove={handleMouseMove}
      onMouseOver={() => setAreaHovered(true)}
      onMouseOut={() => setAreaHovered(false)}
    >
      {areaHovered && (
        <div
          className="absolute py-1 px-2 bg-white border border-slate-300 rounded flex flex-col gap-1 w-max transform -translate-x-1/2 -translate-y-[70px]"
          // Injecting inline styles here, as tailwind can't handle dynamic style values 
          style={{
            top: posY,
            left: posX,
          }}
        >
          <Typography color="secondary" variant="caption">
            X: {posX}
          </Typography>
          <Typography color="secondary" variant="caption">
            Y: {posY}
          </Typography>
        </div>
      )}
    </div>
  );
};