← articleshooks unleashed

useMouseCoords: track cursor position

A custom hook that subscribes to mousemove and returns the latest clientX and clientY.

Tooltips, custom cursors, and drag overlays often need the current mouse position. This hook centralizes the mousemove listener.

The hook

import { useState, useEffect } from "react";

const useMouseCoords = () => {
  const [coords, setCoords] = useState({ x: 0, y: 0 });

  useEffect(() => {
    const handleMouseMove = (event) => {
      setCoords({ x: event.clientX, y: event.clientY });
    };

    window.addEventListener("mousemove", handleMouseMove);
    return () => window.removeEventListener("mousemove", handleMouseMove);
  }, []);

  return coords;
};

export default useMouseCoords;

How it works

State holds { x, y } in viewport coordinates (clientX / clientY). A single mousemove listener on window updates state on every move. The effect cleanup removes the listener when the component unmounts.

Example: live coordinates

import React from 'react';
import useMouseCoords from './useMouseCoords';

const CursorDebug = () => {
  const { x, y } = useMouseCoords();

  return (
    <div className="cursor-debug">
      <p>
        Mouse: {x}, {y}
      </p>
    </div>
  );
};

export default CursorDebug;

Notes

  • mousemove fires often. If you render something expensive on every update, throttle or sample the handler.
  • For element-relative coordinates, use getBoundingClientRect() and subtract the target's offset from clientX / clientY.
  • On touch devices, pair this with touchmove if you need the same behavior without a mouse.