npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-best-merge-refs

v1.0.2

Published

React utility to merge multiple refs. Fully correct behavior, matching React 19.

Downloads

158

Readme

react-best-merge-refs 🔗

React utility to merge multiple refs into a single one.

Fully correct behavior, matching React 19. See "Why would I need this?" for an explanation, and "Why not other ref merging libraries?" for additional details on what other ref merging libraries get wrong.

$ npm install react-best-merge-refs

Example

import type { Ref } from 'react';
import { useMergeRefs } from 'react-best-merge-refs';

function AutoFocusedInput({ ref }: { ref?: Ref<HTMLInputElement> }) {
  // Wrap our ref function in `useCallback` to make it stable across renders.
  const autoFocusRef = useCallback((input: HTMLInputElement | null) => {
    input?.focus();
  }, []);

  return (
    <input
      // Even if `ref` might be unstable (since we don't control the consumer of this component),
      // our `autoFocusRef` is guaranteed to only be called once per mount, no spurious calls on
      // re-render.
      ref={useMergeRefs({ ref, autoFocusRef })}
    />
  );
}

FAQ

Why would I need this?

Low-level UI components often need to use their own refs, while also fowarding external ones, like this:

import type { Ref } from 'react';

function MyInput({ ref }: { ref?: Ref<HTMLInputElement> }) {
  const inputRef = useRef<HTMLInputElement>(null);
  /* ... do stuff with `inputRef` ... */

  // How can we pass both `inputRef` and the external `ref` here?
  return <input ref={/* ... */} />;
}

React does not offer a way to set two refs inside the ref property (see facebook/react#29757). This small utility allow you to combine multiple refs into a single ref that you can pass around like this:

import type { Ref } from 'react';
import { useMergeRefs } from 'react-best-merge-refs';

function MyInput({ ref }: { ref?: Ref<HTMLInputElement> }) {
  const inputRef = useRef<HTMLInputElement>(null);
  /* ... do stuff with `inputRef` ... */

  return <input ref={useMergeRefs({ ref, inputRef })} />;
}

The advantage of using this library is that we will keep compatibility with React semantics for you.

Why not other ref merging libraries?

React 19 introduced cleanup functions for refs and this library has full support for them, completely providing the same guarantees that React provides for you, exactly as if you were using individual refs.

React refs are subtle and merging is easy to implement wrong. The fantastic react-merge-refs library is a great implementation, but has a subtle issue with unstable refs that (1) completely breaks React's contract for refs and, worst of it, (2) cannot be fixed without patching the broken library (your refs are subtly broken as long as anyone merges them with unstable refs).

See "Example" for a very common use case that is broken in other libraries. This pattern is so common across the whole React ecosystem, I'm pretty sure most merged refs are subtly broken everywhere!

Why an object for refs instead of a simple array?

Other merging libraries allow you to pass the refs as an array (or multiple arguments), but this can lead to subtle bugs under some circumstances since the refs are implicitly ordered.

Similar to React's key prop we need to track individual refs over time (regardless of their order) to abide to React's ref semantics. For example, if we allowed an array and someone compiled a list of refs like this:

function BuggyComponent({
  ref,
  onDomReady,
}: {
  ref?: Ref<HTMLInputElement>;
  onDomReadyCallbacks: (() => {})[];
}) {
  return <input ref={useMergeRefs([...onDomReadyCallbacks, ref])} />;
}

...if a callback is added or removed in onDomReadyCallbacks, refs will be considered as having changed, including calling ref unexpectedly and breaking React's guarantees for anyone using your component.

Since merging refs can break the contract even for refs that are external to your code, it is very important to keep the API foolproof and prevent doing the wrong thing. You probably have some sort of stable id (like the one you'd use for a key prop) and if you don't you can always resort to using indices as keys as a last resort (again, like React's key prop).

By forcing all refs to be keyed (and thus explicitly unordered) we can safely track additions and removals without breaking external refs by mistake.

License (MIT)

Copyright 2025 Álvaro Cuesta (alvaro-cuesta@GitHub)

Licensed under the MIT license.