useMergedRefs

useMergedRefs is a hook that merges multiple refs into a single ref. Use this hook when you need to use more than one ref on a single dom node.

useMergedRefs accepts any number of refs (callback refs, RefObjects, or undefined) and returns a single callback ref that forwards the DOM node to all of them. This eliminates the need to manually synchronize multiple refs on the same element. The returned ref is stable and handles both ref objects and callback refs uniformly.

When to Use

  • Combining a forwarded ref from React.forwardRef with an internal ref used by another hook (e.g., useHover, useFocus)
  • Attaching multiple independent behaviors (measurement, intersection observation, drag handling) to the same DOM element
  • Building compound components or component libraries where both the library and the consumer need ref access

Notes

  • Handles all ref types: Works with RefObject, callback refs, and undefined values seamlessly.
  • SSR-safe: The returned callback ref does not access any browser APIs on its own.
  • See also useHover and other element hooks that accept refs, which can be combined via useMergedRefs.

Usage

Live Editor
function Demo() {
  const hoverRef = useRef(null);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const isHovered = useHover(hoverRef);
  const [isFocused, toggleFocus] = useToggle(false);

  const mergedRef = useMergedRefs(hoverRef, buttonRef);

  useEffect(() => {
    const handleKeyPress = (event) => {
      if (event.key === 'f' || event.key === 'F') {
        buttonRef.current?.focus();
      }
    };

    window.addEventListener('keypress', handleKeyPress);

    return () => {
      window.removeEventListener('keypress', handleKeyPress);
    };
  }, []);

  const handleFocus = () => toggleFocus(true);
  const handleBlur = () => toggleFocus(false);

  return (
    <div>
      <button
        ref={mergedRef}
        onFocus={handleFocus}
        onBlur={handleBlur}
        style={{
          padding: '10px 20px',
          backgroundColor: isHovered ? 'lightblue' : isFocused ? 'lightyellow' : 'white',
          border: '1px solid black',
          cursor: 'pointer',
          outline: isFocused ? '2px solid blue' : 'none',
        }}
      >
        {isHovered ? 'Hovered!' : isFocused ? 'Focused!' : 'Hover or Focus me'}
      </button>
      <p>Press 'F' key to focus the button</p>
    </div>
  );
};

render(<Demo/>);
Result

API

useMergedRef

Returns

(node: T | null) => void: A function that merges multiple refs

Arguments

ArgumentDescriptionTypeDefaultValue
refs-PossibleRef<T>[]-

PossibleRef

export type PossibleRef<T> = Ref<T> | undefined;