How to Update Forwarding Refs in React

Updating forwarding refs in React allows parent components to directly access, modify, and respond to changes in the DOM nodes of child components. This guide explains how to implement ref forwarding using React’s forwardRef API, how to update ref values dynamically, and how to use callback refs or the useImperativeHandle hook to customize ref updates.

Understanding Ref Forwarding

Ref forwarding is a technique for automatically passing a ref through a component to one of its children. This is particularly useful for reusable component libraries where parent components need to manage focus, selection, or animations of specific child DOM elements.

Here is a basic implementation of ref forwarding:

import { forwardRef } from 'react';

const MyInput = forwardRef((props, ref) => {
  return <input ref={ref} {...props} />;
});

export default MyInput;

In this setup, when a parent component passes a ref to MyInput, the ref is forwarded directly to the HTML <input> element. React automatically updates the ref’s .current property to point to the DOM element once it mounts.

Updating Forwarded Refs Dynamically

In React, the ref object is mutable. The most common way to update a forwarded ref is by interacting with its .current property.

1. Direct DOM Manipulation

Once the ref is forwarded and attached, the parent component can update the DOM node directly:

import { useRef } from 'react';
import MyInput from './MyInput';

function ParentComponent() {
  const inputRef = useRef(null);

  const focusAndClearInput = () => {
    if (inputRef.current) {
      inputRef.current.focus();
      inputRef.current.value = ''; // Direct update to the DOM node
    }
  };

  return (
    <div>
      <MyInput ref={inputRef} />
      <button onClick={focusAndClearInput}>Clear and Focus</button>
    </div>
  );
}

2. Using Callback Refs for Side Effects on Updates

If you need to run code when React updates the ref (for example, when the node attaches or detaches), use a callback ref instead of a standard useRef object.

A callback ref is a function passed to the ref prop. React calls this function with the DOM element when it mounts, and with null when it unmounts.

import { useCallback } from 'react';
import MyInput from './MyInput';

function ParentComponent() {
  const measuredRef = useCallback((node) => {
    if (node !== null) {
      console.log('The input ref has updated. Height is:', node.getBoundingClientRect().height);
    }
  }, []);

  return <MyInput ref={measuredRef} />;
}

3. Customizing the Ref Value with useImperativeHandle

Sometimes you do not want to expose the entire DOM node to the parent. Instead, you can update and customize the exposed ref instance using the useImperativeHandle hook inside the child component.

This allows you to define custom methods that the parent can call to update the child component’s state or trigger specific behaviors.

import { forwardRef, useImperativeHandle, useRef } from 'react';

const CustomInput = forwardRef((props, ref) => {
  const inputRef = useRef(null);

  // Expose custom update functions to the parent
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    },
    setValue: (val) => {
      inputRef.current.value = val;
    }
  }));

  return <input ref={inputRef} {...props} />;
});

// Parent usage:
// inputRef.current.focus();
// inputRef.current.setValue('New Value');

Note on React 19 Updates

If you are using React 19 or later, forwardRef is no longer strictly necessary for standard components. You can pass ref as a normal prop directly into functional components. However, the underlying mechanics of updating the ref via .current or using useImperativeHandle remain identical.