Docs
Cursor TrackerCursor 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, useRef } from "react";
type Point = {
x: number;
y: number;
};
export function useMousePosition(
ref: React.RefObject<HTMLElement | null>,
callback?: (point: Point) => void,
) {
const callbackRef = useRef(callback);
const rectRef = useRef<DOMRect | null>(null);
const frameRef = useRef<number | null>(null);
const latestPointRef = useRef<Point | null>(null);
callbackRef.current = callback;
useEffect(() => {
const node = ref.current;
if (!node) return;
const updateRect = () => {
rectRef.current = node.getBoundingClientRect();
};
const flush = () => {
frameRef.current = null;
if (latestPointRef.current) {
callbackRef.current?.(latestPointRef.current);
}
};
const handlePointerMove = (event: PointerEvent) => {
if (!rectRef.current) {
updateRect();
}
const currentRect = rectRef.current;
if (!currentRect) return;
latestPointRef.current = {
x: event.clientX - currentRect.left,
y: event.clientY - currentRect.top,
};
if (frameRef.current === null) {
frameRef.current = requestAnimationFrame(flush);
}
};
updateRect();
node.addEventListener("pointerenter", updateRect);
node.addEventListener("pointermove", handlePointerMove, {
passive: true,
});
window.addEventListener("resize", updateRect);
window.addEventListener("scroll", updateRect, {
passive: true,
capture: true,
});
return () => {
node.removeEventListener("pointerenter", updateRect);
node.removeEventListener("pointermove", handlePointerMove);
window.removeEventListener("resize", updateRect);
window.removeEventListener("scroll", updateRect, true);
if (frameRef.current !== null) {
cancelAnimationFrame(frameRef.current);
}
};
}, [ref]);
}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.tsxPaste 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 →
</div>
</div>
);
}Credits
Built by hari