DEV Community

Cover image for New way of passing ref to child in React 19
ReactChallenges
ReactChallenges

Posted on

New way of passing ref to child in React 19

If you have worked with refs in React, you probably know they have always felt a bit different from the rest of the API. Useful, yes—but also slightly awkward.

With React 19, that changes. Passing a ref to a child component is now much more natural because ref can be handled like a normal prop. That means less boilerplate, cleaner components, and a simpler mental model.

If you want to try this yourself, the Passing Refs in React 19 challenge on our platform lets you practice exactly this pattern. But first, let's understand what refs are and why the old way was painful.

How refs work (and why they were awkward)

A ref is just a way to keep a direct reference to something rendered by React, usually a DOM element. You normally use refs when you need to do something imperative: focus an input, scroll an element into view, measure size or position, or trigger methods like opening a modal.

function App() {
  const inputRef = useRef<HTMLInputElement>(null);

  return (
    <>
      <button onClick={() => inputRef.current?.focus()}>Focus input</button>

      <input ref={inputRef} />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

The parent owns the button, and the parent decides when the input should be focused. Because of that, the ref also belongs in the parent. The rule is simple: the ref should live wherever the action is controlled.

But what happens when the ref is inside the child?

function Input() {
  const ref = useRef<HTMLInputElement>(null);

  return <input ref={ref} />;
}
Enter fullscreen mode Exit fullscreen mode

Now only the Input component can use that ref. The parent cannot call .focus(), scroll to it, measure it, or control it from outside. The ref becomes private—sometimes fine, but often not what you need.

And here's where the friction came in. Before React 19, ref was treated differently from normal props. You could not simply write <Input ref={inputRef} /> unless that component used forwardRef:

const Input = forwardRef<HTMLInputElement, Props>((props, ref) => {
  return <input ref={ref} {...props} />;
});
Enter fullscreen mode Exit fullscreen mode

It worked, but it came with real costs: extra wrapper syntax, ref behaving differently from props, more complex TypeScript types, and awkward composition with memo or HOCs.

What React 19 changes

Now you can write this:

function Input({ ref, ...props }) {
  return <input ref={ref} {...props} />;
}
Enter fullscreen mode Exit fullscreen mode

No forwardRef. No special wrapper. No separate mental model.

The main benefit is consistency. Before, ref felt like a special exception in React. Now it follows the same idea as everything else: if the parent needs access to something, pass it down. That makes components easier to understand, easier to teach, and reduces noise in codebases full of tiny wrapper components whose only purpose was forwarding refs.

This also helps with advanced patterns. Sometimes you don't want to expose a DOM node—you want to expose methods. For example, a modal:

function Modal({ ref }) {
  const [open, setOpen] = useState(false);

  useImperativeHandle(ref, () => ({
    open: () => setOpen(true),
    close: () => setOpen(false),
  }));

  return open ? <div>Modal</div> : null;
}
Enter fullscreen mode Exit fullscreen mode

Used like this:

function App() {
  const modalRef = useRef(null);

  return (
    <>
      <button onClick={() => modalRef.current.open()}>Open modal</button>

      <Modal ref={modalRef} />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

This pattern still works, but now the component itself is cleaner.

Refs were never difficult because of what they do. They were difficult because React treated them differently.

React 19 removes that friction. A ref is usually owned by the component that needs to use it—most of the time, the parent. The child simply receives that ref and connects it to something useful.

Now that ref behaves like a normal prop, the whole pattern feels much more natural. If you want to solidify this concept, try the Passing Refs in React 19 challenge—it takes just a few minutes.

Top comments (0)