useMousePosition
Creates signals that track the mouse position (x and y coordinates). The signals update when the mouse moves, with throttling to prevent excessive updates.
MDN Reference: MouseEvent
Usage
typescript
import { useMousePosition } from 'ng-reactive-utils';
@Component({
template: `<div>Mouse: {{ mousePosition().x }}, {{ mousePosition().y }}</div>`,
})
class CursorTrackerComponent {
mousePosition = useMousePosition();
}With Custom Throttle
typescript
@Component({
template: `<div>Mouse: {{ mousePosition().x }}, {{ mousePosition().y }}</div>`,
})
class SmoothCursorComponent {
// Use a longer throttle for smoother updates
mousePosition = useMousePosition(200);
}Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
throttleMs | number | 100 | Throttle delay for mouse move events (ms) |
Returns
Signal<{ x: number; y: number }> - A readonly signal containing mouse coordinates
Notes
- Returned signal is readonly to prevent direct manipulation
- Uses
createSharedComposableinternally - usages with the samethrottleMsvalue share a single instance - Different
throttleMsvalues create separate instances with their own event listeners - Throttles mouse move events by default (100ms) to prevent excessive updates
- Event listeners are automatically cleaned up when no more subscribers
Source
ts
import { signal, inject, PLATFORM_ID } from '@angular/core';
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
import throttle from 'lodash-es/throttle';
import { createSharedComposable } from '../../../utils/create-shared-composable/create-shared-composable';
export type MousePosition = { x: number; y: number };
/**
* Creates signals that track the mouse position (x and y coordinates). The signals update
* when the mouse moves, with throttling to prevent excessive updates.
*
* This composable is shared across components with the same parameters in the same injector context.
* Components using the same throttle value share one instance; different values create separate instances.
*
* On the server, returns default values (0, 0) and updates to actual values once hydrated on the client.
*
* @param throttleMs - Throttle delay for mouse move events (default: 100ms)
*
* @example
* ```ts
* // Default throttle (100ms) - shares instance with other components using default
* const mousePosition = useMousePosition();
* const { x, y } = mousePosition();
* ```
*
* @example
* ```ts
* // Custom throttle (200ms) - creates separate instance for this throttle value
* const mousePosition = useMousePosition(200);
* ```
*/
export const useMousePosition = createSharedComposable((throttleMs: number = 100) => {
const document = inject(DOCUMENT);
const platformId = inject(PLATFORM_ID);
const isBrowser = isPlatformBrowser(platformId);
const mousePosition = signal<MousePosition>({ x: 0, y: 0 });
const updatePosition = (event: MouseEvent) => {
mousePosition.set({ x: event.clientX, y: event.clientY });
};
const throttledUpdatePosition = throttle(updatePosition, throttleMs);
// Only set up event listeners in the browser
if (isBrowser && document.defaultView) {
document.defaultView.addEventListener('mousemove', throttledUpdatePosition);
}
return {
value: mousePosition.asReadonly(),
cleanup: () => {
throttledUpdatePosition.cancel();
if (isBrowser && document.defaultView) {
document.defaultView.removeEventListener('mousemove', throttledUpdatePosition);
}
},
};
});