NEW
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
shadcn registry is live·
Learn more
Skip to content
Docs

Cursor Tracker

A wrapper component that tracks the cursor moving within it

requires interactionhover
Loading...

Installation

CLI

pnpm dlx shadcn@latest add https://animata.design/r/container/cursor-tracker.json

Manual

Copy useMousePosition hook

import { useEffect } from "react";
 
export function useMousePosition(
  ref: React.RefObject<HTMLElement | null>,
  callback?: ({ x, y }: { x: number; y: number }) => void,
) {
  useEffect(() => {
    const handleMouseMove = (event: MouseEvent) => {
      const { clientX, clientY } = event;
      const { top, left } = ref.current?.getBoundingClientRect() || {
        top: 0,
        left: 0,
      };
 
      callback?.({ x: clientX - left, y: clientY - top });
    };
 
    const handleTouchMove = (event: TouchEvent) => {
      const { clientX, clientY } = event.touches[0];
      const { top, left } = ref.current?.getBoundingClientRect() || {
        top: 0,
        left: 0,
      };
 
      callback?.({ x: clientX - left, y: clientY - top });
    };
 
    ref.current?.addEventListener("mousemove", handleMouseMove);
    ref.current?.addEventListener("touchmove", handleTouchMove);
 
    const nodeRef = ref.current;
    return () => {
      nodeRef?.removeEventListener("mousemove", handleMouseMove);
      nodeRef?.removeEventListener("touchmove", handleTouchMove);
    };
  }, [ref, callback]);
}

Run the following command

It will create a new file cursor-tracker.tsx inside the components/animata/container directory.

mkdir -p components/animata/container && touch components/animata/container/cursor-tracker.tsx

Paste the code

Open the newly created file and paste the following code:

import { useCallback, useRef } from "react";
 
import { useMousePosition } from "@/hooks/use-mouse-position";
 
export default function CursorTracker() {
  const divRef = useRef<HTMLDivElement>(null);
  const infoRef = useRef<HTMLDivElement>(null);
 
  const update = useCallback(({ x, y }: { x: number; y: number }) => {
    // We need to offset the position to center the info div
    const offsetX = (infoRef.current?.offsetWidth || 0) / 2;
    const offsetY = (infoRef.current?.offsetHeight || 0) / 2;
 
    // Use CSS variables to position the info div instead of state to avoid re-renders
    infoRef.current?.style.setProperty("--x", `${x - offsetX}px`);
    infoRef.current?.style.setProperty("--y", `${y - offsetY}px`);
  }, []);
 
  useMousePosition(divRef, update);
 
  return (
    <div
      ref={divRef}
      className="group/cursor relative w-64 cursor-none rounded-3xl bg-violet-50 p-6 text-violet-800"
    >
      {/* Actual content */}
      <h1 className="mb-4 text-3xl font-semibold leading-none">
        Elevate your design with <span className="underline decoration-wavy">Animata</span>
      </h1>
      <div className="mb-8">
        Move your mouse over the box to reveal the text and the cursor position.
      </div>
 
      {/* Cursor tracker */}
      <div
        ref={infoRef}
        style={{
          transform: "translate(var(--x), var(--y))",
        }}
        className="pointer-events-none absolute left-0 top-0 z-50 rounded-full bg-blue-800/80 px-4 py-2 text-sm font-bold text-white opacity-0 duration-0 group-hover/cursor:opacity-100"
      >
        Read more &rarr;
      </div>
    </div>
  );
}

Credits

Built by hari