@aniruddha1806/use-mouse-move v1.0.1
React useMouseMove Hook
A powerful React hook for tracking mouse position with support for element-specific coordinates, performance optimization through throttling and debouncing, and boundary detection.
Installation
npm install @aniruddha1806/use-mouse-moveFeatures
- đąī¸ Global Mouse Tracking: Track mouse position across the entire viewport
- đ¯ Element-Specific Tracking: Get mouse coordinates relative to any element
- ⥠Performance Optimized: Built-in throttling and debouncing options
- đ Boundary Detection: Know when mouse is within element bounds
- đą Responsive: Works with dynamic element sizes and positions
- đ¨ Flexible: Use for hover effects, drag operations, cursor followers
- đĒļ Lightweight: Zero dependencies beyond React
- đ§ Easy Integration: Simple API with sensible defaults
Quick Start
import { useMouseMove } from '@aniruddha1806/use-mouse-move';
function App() {
const { x, y } = useMouseMove();
return (
<div>
<h1>Mouse Tracker</h1>
<p>Mouse position: ({x}, {y})</p>
</div>
);
}API
Parameters
The hook accepts an options object with the following properties:
| Option | Type | Default | Description |
|---|---|---|---|
element | RefObject<HTMLElement> | null | Element to track mouse position within |
throttle | number | 0 | Throttle updates in milliseconds (0 = disabled) |
debounce | number | 0 | Debounce updates in milliseconds (0 = disabled) |
Returns
The hook returns an object with the following properties:
| Property | Type | Description |
|---|---|---|
x | number | Global mouse X coordinate |
y | number | Global mouse Y coordinate |
elementX | number \| null | Mouse X coordinate relative to element |
elementY | number \| null | Mouse Y coordinate relative to element |
isInBounds | boolean | Whether mouse is within element boundaries |
Examples
Basic Global Mouse Tracking
Track mouse position across the entire viewport:
import { useMouseMove } from '@aniruddha1806/use-mouse-move';
function GlobalMouseTracker() {
const { x, y } = useMouseMove();
return (
<div style={{ height: '100vh', padding: '20px' }}>
<h2>Global Mouse Position</h2>
<p>X: {x}px</p>
<p>Y: {y}px</p>
{/* Visual indicator */}
<div
style={{
position: 'fixed',
left: x - 5,
top: y - 5,
width: '10px',
height: '10px',
backgroundColor: 'red',
borderRadius: '50%',
pointerEvents: 'none',
zIndex: 9999,
}}
/>
</div>
);
}Element-Specific Mouse Tracking
Track mouse position relative to a specific element:
import { useRef } from 'react';
import { useMouseMove } from '@aniruddha1806/use-mouse-move';
function ElementMouseTracker() {
const boxRef = useRef(null);
const { x, y, elementX, elementY, isInBounds } = useMouseMove({
element: boxRef
});
return (
<div style={{ padding: '20px' }}>
<h2>Element Mouse Tracking</h2>
<div
ref={boxRef}
style={{
width: '400px',
height: '300px',
border: '2px solid #333',
backgroundColor: isInBounds ? '#e8f5e8' : '#f5f5f5',
position: 'relative',
margin: '20px 0',
}}
>
<div style={{ padding: '10px' }}>
<p>Global: ({x}, {y})</p>
<p>Element: ({elementX}, {elementY})</p>
<p>In bounds: {isInBounds ? 'Yes' : 'No'}</p>
</div>
{/* Show mouse position within element */}
{isInBounds && (
<div
style={{
position: 'absolute',
left: elementX - 5,
top: elementY - 5,
width: '10px',
height: '10px',
backgroundColor: 'blue',
borderRadius: '50%',
pointerEvents: 'none',
}}
/>
)}
</div>
</div>
);
}Performance Optimization with Throttling
Use throttling to limit update frequency for better performance:
import { useMouseMove } from '@aniruddha1806/use-mouse-move';
function ThrottledMouseTracker() {
// Update position at most every 16ms (~60fps)
const { x, y } = useMouseMove({ throttle: 16 });
return (
<div style={{ height: '100vh', padding: '20px' }}>
<h2>Throttled Mouse Tracking (60fps)</h2>
<p>Position: ({x}, {y})</p>
<p>Updates are throttled to ~60fps for smooth performance</p>
{/* Smooth following cursor */}
<div
style={{
position: 'fixed',
left: x - 25,
top: y - 25,
width: '50px',
height: '50px',
backgroundColor: 'rgba(0, 123, 255, 0.7)',
borderRadius: '50%',
pointerEvents: 'none',
transition: 'transform 0.1s ease-out',
transform: 'scale(1)',
}}
/>
</div>
);
}Debounced Mouse Tracking
Use debouncing to delay updates until mouse stops moving:
import { useState } from 'react';
import { useMouseMove } from '@aniruddha1806/use-mouse-move';
function DebouncedMouseTracker() {
const [lastStoppedPosition, setLastStoppedPosition] = useState({ x: 0, y: 0 });
// Update position only after mouse stops moving for 300ms
const { x, y } = useMouseMove({ debounce: 300 });
// Update stopped position when debounced position changes
React.useEffect(() => {
setLastStoppedPosition({ x, y });
}, [x, y]);
return (
<div style={{ height: '100vh', padding: '20px' }}>
<h2>Debounced Mouse Tracking</h2>
<p>Move your mouse around and stop...</p>
<p>Last stopped position: ({lastStoppedPosition.x}, {lastStoppedPosition.y})</p>
{/* Show marker where mouse last stopped */}
<div
style={{
position: 'fixed',
left: lastStoppedPosition.x - 10,
top: lastStoppedPosition.y - 10,
width: '20px',
height: '20px',
backgroundColor: 'green',
borderRadius: '50%',
pointerEvents: 'none',
}}
/>
</div>
);
}Interactive Hover Effects
Create interactive hover effects using element tracking:
import { useRef } from 'react';
import { useMouseMove } from '@aniruddha1806/use-mouse-move';
function InteractiveCard() {
const cardRef = useRef(null);
const { elementX, elementY, isInBounds } = useMouseMove({
element: cardRef,
throttle: 16
});
// Calculate rotation based on mouse position
const getRotation = () => {
if (!isInBounds || !cardRef.current) return { rotateX: 0, rotateY: 0 };
const { clientWidth, clientHeight } = cardRef.current;
const centerX = clientWidth / 2;
const centerY = clientHeight / 2;
const rotateX = ((elementY - centerY) / centerY) * -10;
const rotateY = ((elementX - centerX) / centerX) * 10;
return { rotateX, rotateY };
};
const { rotateX, rotateY } = getRotation();
return (
<div style={{ padding: '50px', display: 'flex', justifyContent: 'center' }}>
<div
ref={cardRef}
style={{
width: '300px',
height: '200px',
backgroundColor: '#fff',
borderRadius: '12px',
boxShadow: '0 10px 30px rgba(0,0,0,0.2)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer',
transform: `perspective(1000px) rotateX(\${rotateX}deg) rotateY(\${rotateY}deg) scale(\${isInBounds ? 1.05 : 1})`,
transition: isInBounds ? 'none' : 'transform 0.3s ease-out',
}}
>
<div style={{ textAlign: 'center' }}>
<h3>Interactive Card</h3>
<p>Hover to see 3D effect</p>
{isInBounds && (
<p style={{ fontSize: '12px', color: '#666' }}>
Mouse: ({Math.round(elementX)}, {Math.round(elementY)})
</p>
)}
</div>
</div>
</div>
);
}Cursor Follower
Create a custom cursor that follows the mouse:
import { useMouseMove } from '@aniruddha1806/use-mouse-move';
function CursorFollower() {
const { x, y } = useMouseMove({ throttle: 8 });
return (
<div style={{ height: '100vh', cursor: 'none' }}>
<div style={{ padding: '20px' }}>
<h2>Custom Cursor Follower</h2>
<p>Move your mouse around to see the custom cursor</p>
<button style={{ margin: '10px', padding: '10px 20px' }}>
Hover me
</button>
<button style={{ margin: '10px', padding: '10px 20px' }}>
And me
</button>
</div>
{/* Custom cursor */}
<div
style={{
position: 'fixed',
left: x,
top: y,
width: '20px',
height: '20px',
backgroundColor: 'rgba(255, 0, 150, 0.8)',
borderRadius: '50%',
pointerEvents: 'none',
zIndex: 9999,
transform: 'translate(-50%, -50%)',
transition: 'transform 0.1s ease-out',
}}
/>
{/* Cursor trail */}
<div
style={{
position: 'fixed',
left: x,
top: y,
width: '40px',
height: '40px',
border: '2px solid rgba(255, 0, 150, 0.3)',
borderRadius: '50%',
pointerEvents: 'none',
zIndex: 9998,
transform: 'translate(-50%, -50%)',
transition: 'all 0.2s ease-out',
}}
/>
</div>
);
}Drawing Canvas
Use mouse tracking for drawing applications:
import { useRef, useState, useEffect } from 'react';
import { useMouseMove } from '@aniruddha1806/use-mouse-move';
function DrawingCanvas() {
const canvasRef = useRef(null);
const [isDrawing, setIsDrawing] = useState(false);
const [lastPosition, setLastPosition] = useState({ x: 0, y: 0 });
const { elementX, elementY, isInBounds } = useMouseMove({
element: canvasRef,
throttle: 8
});
// Handle drawing
useEffect(() => {
if (!isDrawing || !isInBounds || !canvasRef.current) return;
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(lastPosition.x, lastPosition.y);
ctx.lineTo(elementX, elementY);
ctx.stroke();
setLastPosition({ x: elementX, y: elementY });
}, [elementX, elementY, isDrawing, isInBounds, lastPosition]);
const startDrawing = (e) => {
setIsDrawing(true);
setLastPosition({ x: elementX, y: elementY });
};
const stopDrawing = () => {
setIsDrawing(false);
};
const clearCanvas = () => {
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
};
return (
<div style={{ padding: '20px' }}>
<h2>Drawing Canvas</h2>
<p>Click and drag to draw</p>
<div style={{ marginBottom: '10px' }}>
<button onClick={clearCanvas}>Clear Canvas</button>
</div>
<canvas
ref={canvasRef}
width={600}
height={400}
onMouseDown={startDrawing}
onMouseUp={stopDrawing}
onMouseLeave={stopDrawing}
style={{
border: '2px solid #333',
cursor: 'crosshair',
backgroundColor: 'white',
}}
/>
<p style={{ marginTop: '10px', fontSize: '14px', color: '#666' }}>
Mouse: ({Math.round(elementX || 0)}, {Math.round(elementY || 0)}) |
Drawing: {isDrawing ? 'Yes' : 'No'}
</p>
</div>
);
}TypeScript Usage
The hook provides full TypeScript support:
import { useRef } from 'react';
import { useMouseMove } from '@aniruddha1806/use-mouse-move';
interface MousePosition {
x: number;
y: number;
elementX: number | null;
elementY: number | null;
isInBounds: boolean;
}
interface UseMouseMoveOptions {
element?: React.RefObject<HTMLElement> | null;
throttle?: number;
debounce?: number;
}
function TypedMouseTracker() {
const elementRef = useRef<HTMLDivElement>(null);
// Hook with typed options
const options: UseMouseMoveOptions = {
element: elementRef,
throttle: 16,
debounce: 0
};
// Destructure with proper typing
const mouseData: MousePosition = useMouseMove(options);
const { x, y, elementX, elementY, isInBounds } = mouseData;
return (
<div>
<div ref={elementRef} style={{ width: 300, height: 200, border: '1px solid #ccc' }}>
<p>Global: ({x}, {y})</p>
<p>Element: ({elementX}, {elementY})</p>
<p>In bounds: {isInBounds.toString()}</p>
</div>
</div>
);
}
// Custom hook using useMouseMove
function useMouseDistance(elementRef: React.RefObject<HTMLElement>) {
const { elementX, elementY, isInBounds } = useMouseMove({
element: elementRef,
throttle: 16
});
const distance = React.useMemo(() => {
if (!isInBounds || elementX === null || elementY === null || !elementRef.current) {
return 0;
}
const centerX = elementRef.current.clientWidth / 2;
const centerY = elementRef.current.clientHeight / 2;
return Math.sqrt(
Math.pow(elementX - centerX, 2) + Math.pow(elementY - centerY, 2)
);
}, [elementX, elementY, isInBounds, elementRef]);
return { distance, isInBounds };
}Performance Tips
1. Use Throttling for Smooth Animations
For smooth 60fps animations, use a 16ms throttle:
const { x, y } = useMouseMove({ throttle: 16 });2. Use Debouncing for Expensive Operations
For operations that don't need real-time updates:
const { x, y } = useMouseMove({ debounce: 100 });3. Combine with useMemo for Complex Calculations
const { elementX, elementY } = useMouseMove({ element: ref });
const expensiveCalculation = useMemo(() => {
// Expensive calculation based on mouse position
return complexFunction(elementX, elementY);
}, [elementX, elementY]);