Skip to content

useMouseInElement

Tracks the mouse cursor position relative to a DOM element and reports whether the cursor is inside or outside it. Observes mousemove, document mouseleave, ResizeObserver, MutationObserver (style/class attribute changes), and window scroll/resize events to keep values accurate as the element moves or resizes. All return values are reactive Observable<number | boolean>.

elementX: 0pxelementY: 0pxisOutside: truewidth: 0pxheight: 0pxx (global): 0px
move your mouse here
import {
function useRef$<T extends Element = Element>(externalRef?: React.Ref<T> | null): Ref$<T>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
,
import useMouseInElement
useMouseInElement
} from "@usels/core";
function
function Component(): React.JSX.Element
Component
() {
const
const el$: Ref$<HTMLDivElement>
el$
=
useRef$<HTMLDivElement>(externalRef?: React.Ref<HTMLDivElement> | undefined): Ref$<HTMLDivElement>

Creates an observable element ref. Can be used as a drop-in replacement for useRef, composed with callback refs, or used with forwardRef.

The element is wrapped with opaqueObject to prevent legendapp/state from making DOM properties reactive (deep observation).

@paramexternalRef - Optional. Accepts callback ref, RefObject, or null (forwardRef compatible).

@returnsA callable ref that is also observable via get/peek

@example

// standalone — useRef replacement
const el$ = useRef$<HTMLDivElement>();
return <div ref={el$} />;
// forwardRef compatible
const Component = forwardRef<HTMLDivElement>((props, ref) => {
const el$ = useRef$(ref);
return <div ref={el$} />;
});
// callback ref composition
const myRef = useCallback((node: HTMLDivElement | null) => {
node?.focus();
}, []);
const el$ = useRef$(myRef);
return <div ref={el$} />;

useRef$
<
interface HTMLDivElement
HTMLDivElement
>();
const {
const elementX$: any
elementX$
,
const elementY$: any
elementY$
,
const isOutside$: any
isOutside$
} =
import useMouseInElement
useMouseInElement
(
const el$: Ref$<HTMLDivElement>
el$
);
return (
<
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
React.RefAttributes<HTMLDivElement>.ref?: React.Ref<HTMLDivElement> | undefined

Allows getting a ref to the component instance. Once the component unmounts, React will set ref.current to null (or call the ref with null if you passed a callback ref).

ref
={
const el$: Ref$<HTMLDivElement>
el$
}>{
const isOutside$: any
isOutside$
.
any
get
() ? "outside" : `${
const elementX$: any
elementX$
.
any
get
()}, ${
const elementY$: any
elementY$
.
any
get
()}`}</
React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div
>
);
}

By default elementX$/elementY$ continue to update even when the cursor leaves the element. Pass handleOutside: false to freeze the last in-element position once the cursor exits.

const { elementX$, elementY$ } = useMouseInElement(el$, { handleOutside: false });
const { elementX$, elementY$ } = useMouseInElement(el$, {
windowScroll: false,
windowResize: false,
});
const {
const elementX$: any
elementX$
,
const elementY$: any
elementY$
,
const stop: any
stop
} =
import useMouseInElement
useMouseInElement
(
const el$: Ref$<HTMLDivElement>
el$
);
// Tear down all event listeners and observers
const stop: any
stop
();

The raw clientX / clientY values are also exposed as x$ and y$.

const {
const x$: any
x$
,
const y$: any
y$
,
const elementX$: any
elementX$
,
const elementY$: any
elementY$
} =
import useMouseInElement
useMouseInElement
(
const el$: Ref$<HTMLDivElement>
el$
);
export interface UseMouseInElementOptions {
handleOutside?: boolean;
windowScroll?: boolean;
windowResize?: boolean;
}
export interface UseMouseInElementReturn {
elementX$: Observable<number>;
elementY$: Observable<number>;
elementPositionX$: Observable<number>;
elementPositionY$: Observable<number>;
elementWidth$: Observable<number>;
elementHeight$: Observable<number>;
isOutside$: Observable<boolean>;
x$: Observable<number>;
y$: Observable<number>;
stop: () => void;
}
export declare function useMouseInElement(target: MaybeElement, options?: DeepMaybeObservable<UseMouseInElementOptions>): UseMouseInElementReturn;

View on GitHub

  • tigerwest
  • a7392ab 2026-03-06 - feat(core,browser): add sync strategy hooks (tigerwest)