Skip to content

shadcn.io is an independent project built on shadcn/ui

Docs

Free

useMousePosition for React

Tracks the pointer in page coordinates, and inside an element given its ref. For React, when you build a custom cursor, a follow tooltip or a canvas.

useMousePosition returns the pointer position on the page. Put the ref on an element and the same tuple also carries coordinates inside that element.

Page coordinates include scroll. To measure the element box instead of the pointer, use useResizeObserver. In React the numbers start at zero, and the listener attaches after the first paint.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.
Use email insteadNo credit card

Anatomy

useMousePosition anatomy: useMousePosition(), ref, elementX, elementY, position

Usage

import { useMousePosition } from "@/hooks/use-mouse-position";
const [position, ref] = useMousePosition<HTMLDivElement>();

Read x and y for the page. Attach the ref to also receive elementX and elementY, measured from the element's top-left.

FAQ

How do I get coordinates inside an element?

Put the ref from the tuple on the element. On each move the hook reads that element's rectangle, adds the page scroll, and subtracts the result from the page coordinates. elementX and elementY are those differences. elementPositionX and elementPositionY are the element's top-left on the page. Until the ref points at an element, only x and y are set.

Do the coordinates include scroll?

Yes. x and y come from pageX and pageY, which measure from the document rather than the current viewport. Element coordinates start from getBoundingClientRect, then add scrollX and scrollY, so scrolling the page does not move the origin. The hook does not listen to scroll by itself. The numbers refresh on the next mousemove.

Does this track touch?

No. The only listener is mousemove on the document. A finger does not fire that event, so the stored position stays where it was. There is no pointermove or touchmove subscription. If you need mouse and touch together, use a different listener. The coordinates start at zero and stay there until a mouse actually moves.

What does the server return?

x and y are zero, and the element fields are absent, because the listener is added in an effect. Render does not read window, so the server HTML matches the client's first paint. After mount, one document listener is attached. Each move replaces the whole position object. Unmounting removes the listener.

Which element type does the ref expect?

The generic is the element you will attach, and it has to extend HTMLElement. A call for a div gives you a ref whose current value starts as null and later holds that div. The hook checks that the node is an element before it reads a rectangle. Leave the ref unset and you still get page coordinates.

How often does it re-render?

Once per mousemove for as long as the component is mounted. Every event stores a new position object, even when the numbers barely change. That suits a badge or a small preview. A heavy render should not subscribe here, because the hook does not throttle and it does not pause when the pointer leaves the element.

API Reference

Returns

ValueType
[0] positionPosition

Where the pointer is.

position.elementPositionX?number

The element's left edge, from the page's left. With the ref attached.

position.elementPositionY?number

The element's top edge, from the page's top. With the ref attached.

position.elementX?number

The pointer's distance from the element's left edge. With the ref attached.

position.elementY?number

The pointer's distance from the element's top edge. With the ref attached.

position.xnumber

The pointer's distance from the page's left (pageX).

position.ynumber

The pointer's distance from the page's top (pageY).

[1] refReact.RefObject<T | null>

Attach to an element to get positions relative to it too.

Type
React.RefObject<T | null>