What is `forwardRef()` in React used for?
TL;DR
As of React 19 (December 2024), forwardRef() is deprecated. Function components can now accept ref as a regular prop, so wrapping in forwardRef() is no longer required. forwardRef() historically existed because, before React 19, function components could not receive a ref prop and forwardRef() was the official workaround for forwarding a parent's ref down to a child DOM node or component.
// Modern (React 19+): ref is a regular propfunction MyInput({ ref, ...props }) {return <input ref={ref} {...props} />;}// Legacy (React 18 and earlier): wrap with forwardRefimport { forwardRef } from 'react';const MyInputLegacy = forwardRef((props, ref) => (<input ref={ref} {...props} />));
What is forwardRef() in React used for?
The modern answer (React 19+)
In React 19, ref is just a regular prop on function components. You can destructure it like any other prop and pass it through to a DOM element or child component. There is no longer any reason to reach for forwardRef() in new code:
import { useRef } from 'react';function MyInput({ ref, ...props }) {return <input ref={ref} {...props} />;}function ParentComponent() {const inputRef = useRef(null);const focusInput = () => {inputRef.current?.focus();};return (<div><MyInput ref={inputRef} placeholder="Type here..." /><button onClick={focusInput}>Focus Input</button></div>);}
The React team ships a codemod that automatically converts existing forwardRef() usages to the new prop form. forwardRef() itself still works for now but logs a deprecation warning and is expected to be removed in a future major.
Why forwardRef() existed (legacy context)
Before React 19, ref was a "magic" prop that React intercepted — passing ref to a function component did nothing useful. forwardRef() was the API React provided to opt a function component into receiving a ref alongside its props, so the parent could reach a specific DOM node inside it (e.g. focus an input, measure a node, integrate with imperative third-party libraries).
import { forwardRef, useRef } from 'react';// Legacy pattern — still works in React 19, but deprecatedconst MyInput = forwardRef((props, ref) => <input ref={ref} {...props} />);function ParentComponent() {const inputRef = useRef(null);return <MyInput ref={inputRef} placeholder="Type here..." />;}
useImperativeHandle
When you want to expose a custom imperative API to the parent (rather than the raw DOM node), pair ref with useImperativeHandle. This is unchanged in React 19 — only the ref-forwarding mechanism has changed.
import { useImperativeHandle, useRef } from 'react';function FancyInput({ ref }) {const inputRef = useRef(null);useImperativeHandle(ref,() => ({focus: () => inputRef.current?.focus(),clear: () => {if (inputRef.current) inputRef.current.value = '';},}),[],);return <input ref={inputRef} />;}
The parent now sees { focus, clear } on the ref instead of the underlying input element. Use this sparingly — it is an escape hatch out of the declarative model.
Things to keep in mind
- Class components: A
refattached to a class component receives the class instance directly. They have never neededforwardRef(), and that is unchanged. - Forward to a DOM node or imperative handle: A ref must ultimately be attached to a DOM element, a class instance, or an object returned from
useImperativeHandle. Forwarding it to another function component just makes that component the new owner of the ref prop. - Migration: If you maintain a library that ships
forwardRef-wrapped components, dropping the wrapper requires a peer-dependency bump to React 19. Many libraries currently ship both forms during the transition.