Back to Blog
ReactJS

Mastering React forwardRef: A Deep Dive with Examples & Use Cases

10/15/2025
5 min read
 Mastering React forwardRef: A Deep Dive with Examples & Use Cases

Struggling to pass refs to child components? Our in-depth guide explains React forwardRef with practical examples, real-world use cases, and best practices. Level up your React skills!

 Mastering React forwardRef: A Deep Dive with Examples & Use Cases

Mastering React forwardRef: A Deep Dive with Examples & Use Cases

Mastering React forwardRef: A Deep Dive with Examples & Use Cases

If you've been working with React for a while, you've undoubtedly fallen in love with its component-based architecture and one-way data flow. Props flow down from parent to child, and that's usually all you need. But sometimes, you encounter a situation where you need to break this pattern. You need to reach down into a child component and interact with a specific DOM element or one of its methods directly.

This is where the concept of "refs" comes in. And when you try to pass a ref as a prop to a custom component, you hit a wall. The ref doesn't get passed through; it just doesn't work. If you've been frustrated by this, you're not alone.

Welcome to the solution: React.forwardRef.

In this comprehensive guide, we're not just going to scratch the surface. We'll dive deep into what forwardRef is, why it's necessary, and how to use it effectively in real-world scenarios. By the end, you'll be wielding forwardRef with confidence, making your React components more powerful and reusable than ever.

What Exactly is React forwardRef?

Let's start with the official definition. React.forwardRef is a function that lets you automatically pass a ref through a component to one of its children.

Think of it as a secure tunnel that allows a ref to travel through a component, bypassing the normal prop system, and reaching its intended target—usually a native DOM element (like an <input> or <div>) inside the child component.

The Problem: Why Do We Need forwardRef?

To understand the solution, we must first grasp the problem. In React, ref is a special attribute, much like key. It's not a prop. When you create a custom component, React does not forward ref attributes to the underlying DOM element.

Let's look at a classic example. Imagine you have a custom Button component.

jsx

// Child Component: FancyButton.jsx
function FancyButton(props) {
  return (
    <button className="fancy-button">
      {props.children}
    </button>
  );
}

// Parent Component: App.jsx
function App() {
  // We create a ref to focus the button on page load
  const buttonRef = useRef(null);

  useEffect(() => {
    if (buttonRef.current) {
      buttonRef.current.focus(); // This will FAIL!
    }
  }, []);

  return (
    <div>
      {/* We try to pass the ref, but it won't work */}
      <FancyButton ref={buttonRef}>Click Me!</FancyButton>
    </div>
  );
}

In this code, buttonRef.current will not point to the actual <button> DOM element. Instead, it will be null or point to the instance of the FancyButton component, which doesn't have a .focus() method. This is React's default behavior for good reason—it prevents component internals from being manipulated arbitrarily from the outside, which helps maintain a clean data flow.

So, how do we solve this? We wrap our component with React.forwardRef.

How to Use forwardRef: The Basic Syntax

The forwardRef function takes a component as its argument. This component function now receives two parameters:

  1. props: The regular props passed to the component.

  2. ref: The second argument is the ref attribute passed from the parent.

Here's how we fix our FancyButton component:

jsx

// Child Component: FancyButton.jsx
const FancyButton = React.forwardRef((props, ref) => {
  return (
    {/* We attach the ref to the actual <button> element */}
    <button ref={ref} className="fancy-button">
      {props.children}
    </button>
  );
});

// Parent Component: App.jsx
function App() {
  const buttonRef = useRef(null);

  useEffect(() => {
    if (buttonRef.current) {
      buttonRef.current.focus(); // This now WORKS!
      buttonRef.current.style.backgroundColor = 'lightblue';
    }
  }, []);

  return (
    <div>
      <FancyButton ref={buttonRef}>Click Me!</FancyButton>
    </div>
  );
}

Voilà! Now, buttonRef.current directly references the native <button> element. We can call DOM methods like .focus(), .blur(), or change its style directly.

Beyond the DOM: Real-World Use Cases for forwardRef

While focusing an input is the "Hello World" of forwardRef, its power extends much further. Let's explore some practical, real-world scenarios.

1. Integrating with Third-Party Libraries

Many third-party libraries, especially those not built specifically for React (like animation or charting libraries), require a direct reference to a DOM element to function.

jsx

// A component that integrates a non-React animation library
const AnimatedDiv = React.forwardRef((props, ref) => {
  // We use the ref to get the DOM node for the library
  const internalRef = useRef();

  useEffect(() => {
    // Imagine `ThirdPartyAnimationLib` needs the raw DOM element
    const animation = new ThirdPartyAnimationLib(internalRef.current, props.config);
    animation.start();
    return () => animation.stop();
  }, [props.config]);

  // We merge the external forwardRef and our internal ref
  return <div ref={(node) => { internalRef.current = node; if (ref) ref.current = node; }} {...props} />;
});

// Parent can now also get a ref to this div if needed
function Parent() {
  const divRef = useRef();
  // ... use divRef for something else
  return <AnimatedDiv ref={divRef} config={{...}} />;
}

2. Building Reusable Component Libraries

If you're building a library of reusable UI components (like a custom design system), using forwardRef is a best practice. It gives the consumers of your library the flexibility to use refs on your components just as they would on native HTML elements.

Imagine a CustomInput component in your library:

jsx

const CustomInput = React.forwardRef(({ label, ...props }, ref) => {
  return (
    <div className="input-wrapper">
      <label>{label}</label>
      <input ref={ref} {...props} />
    </div>
  );
});

// A developer using your library can now use it seamlessly
function LoginForm() {
  const emailRef = useRef();
  const passwordRef = useRef();

  const handleLogin = () => {
    // Directly access input values or methods
    console.log(emailRef.current.value);
  };

  return (
    <form>
      <CustomInput label="Email" type="email" ref={emailRef} />
      <CustomInput label="Password" type="password" ref={passwordRef} />
      <button type="button" onClick={handleLogin}>Login</button>
    </form>
  );
}

3. Imperative Handle with useImperativeHandle

Sometimes, you don't want to expose the entire DOM node to the parent. Maybe you only want to expose specific methods. This is where useImperativeHandle comes in. It's the perfect companion to forwardRef.

Let's create a PlayPauseVideo component where the parent can only play and pause the video, not change its src or other properties directly.

jsx

const PlayPauseVideo = React.forwardRef((props, ref) => {
  const videoRef = useRef();

  // We customize the instance value that is exposed to the parent component
  useImperativeHandle(ref, () => ({
    play() {
      videoRef.current.play();
    },
    pause() {
      videoRef.current.pause();
    },
    // We can choose NOT to expose videoRef.current entirely
  }), []); // Dependency array for the function

  return <video ref={videoRef} src={props.src} />;
});

function App() {
  const videoPlayerRef = useRef();

  return (
    <div>
      <button onClick={() => videoPlayerRef.current?.play()}>Play</button>
      <button onClick={() => videoPlayerRef.current?.pause()}>Pause</button>
      <PlayPauseVideo ref={videoPlayerRef} src="/my-video.mp4" />
    </div>
  );
}

Now, videoPlayerRef.current only has the play and pause methods. It doesn't have direct access to the full <video> element, which is a much cleaner and more controlled API.

Best Practices and Common Pitfalls

  1. Don't Overuse Refs: The React mantra is "props down, actions up." If you can solve a problem with state and props, you should. Refs are an escape hatch. Use them for imperative actions (focus, scroll, media playback), integrating with non-React libraries, or triggering animations.

  2. Use useImperativeHandle to Limit Exposure: As shown above, this Hook is excellent for creating a clean, controlled API for your components, preventing parents from doing anything they shouldn't.

  3. Forward Ref in Library Components: If you are building a component that will be used by others, wrapping it in forwardRef is a considerate and professional practice.

  4. Combine with useCallback for Function Refs: If you need to use a callback ref inside a forwardRef component, make sure to memoize it with useCallback to avoid unnecessary re-renders.

Mastering concepts like forwardRef is what separates hobbyists from professional developers. It's a key tool for building robust, flexible, and enterprise-grade React applications. If you're looking to solidify your understanding of React and other in-demand technologies, CoderCrafter offers a structured path to success. To learn professional software development courses such as Python Programming, Full Stack Development, and the MERN Stack, visit and enroll today at codercrafter.in.

Frequently Asked Questions (FAQs)

Q: Can I forward a ref to a class component?
A: Yes, but it works a bit differently. The ref will point to the class component instance, not a specific DOM element inside it. To achieve a similar effect, you would define a method in the class (e.g., focusInput()) that the parent can call via the ref.

Q: What if my component is wrapped in React.memo?
A: You can compose them. Wrap your component in forwardRef first, then in memo.

jsx

const FancyButton = React.memo(React.forwardRef((props, ref) => {
  // ... component logic
}));

Q: Is it okay to use forwardRef for everything?
A: Absolutely not. It should be used sparingly. Overusing forwardRef can make your data flow harder to understand and debug. Always prefer declarative props for most communication between components.

Conclusion

React.forwardRef is a powerful feature that elegantly solves the problem of accessing DOM elements and imperative methods inside child components. It's essential for creating highly reusable component libraries, integrating with third-party tools, and handling specific imperative scenarios that fall outside React's declarative model.

Remember, with great power comes great responsibility. Use forwardRef judiciously, pair it with useImperativeHandle for a cleaner API, and always lean towards declarative solutions first.

We hope this deep dive has demystified forwardRef for you. Keep building, keep learning, and if you're ready to take your coding skills to the next level with project-based, industry-relevant curricula, don't forget to check out the courses at codercrafter.in.

Related Articles

Call UsWhatsApp