The End of an Era: Why React 19 Killed forwardRef
For years, React developers have lived with a specific kind of frustration: the “ref-forwarding tax.” If you wanted to pass a DOM ref through a functional component, you were forced into the forwardRef API. It was a necessary evil, but one that came with significant overhead—both in terms of syntax and, more importantly, in terms of TypeScript complexity.
With the release of React 19, that era has officially come to an end. React 19 treats ref as a standard prop, effectively killing the need for forwardRef in your day-to-day component development.
The Problem with forwardRef
To understand why this is a massive win for developer experience, we have to look at what we are leaving behind. The forwardRef API was designed to solve a specific problem: functional components don’t receive ref as a prop by default. To make them “ref-able,” you had to wrap your component in a higher-order function.
This led to several pain points:
- The Wrapper Tax: Every component needing a ref became a wrapper, increasing the nesting depth of your component tree.
-
Flipped Argument Order: Instead of standard
(props) => ..., you had to remember the specific signature(props, ref) => .... -
TypeScript Gymnastics: Typing a
forwardRefcomponent—especially one that uses generics—is notoriously difficult. It often leads to complexReact.forwardRef<T, P>(...)signatures that are difficult to read and maintain.
The New Way: ref as a Prop
In React 19, ref is just another prop. This means your components can be standard, clean functions. You don’t need to wrap them; you don’t need to change your signature.
Here is what a standard, clean component looks like in the React 19 era:
interface Props {
label: string;
ref?: React.Ref<HTMLInputElement>;
}
const Input = ({ label, ref, ...props }: Props) => (
<div>
<label>{label}</label>
<input ref={ref} {...props} />
</div>
);
Enter fullscreen mode Exit fullscreen mode
That is it. By defining ref as an optional property in your Props interface, you gain all the functionality that previously required forwardRef without any of the boilerplate.
Migrating Your Codebase
Before you start manually refactoring thousands of lines of code, take a deep breath. The React team and the broader ecosystem have provided tools to make this transition painless.
1. Use the Automated Codemod
You don’t have to do this by hand. You can leverage automated codemods to handle the heavy lifting. If you are working in a Next.js environment (or using standard React), you can run the following command:
npx @next/codemod@canary react-19/replace-forwardref
This tool will scan your project, identify forwardRef usages, and convert them to the new standard prop syntax.
2. When to Keep forwardRef
While forwardRef is on a deprecation path for simple DOM forwarding, it hasn’t been removed entirely. If you are using useImperativeHandle to expose custom imperative APIs (methods or values from your component to a parent), forwardRef is still required.
3. Watch Out for Ref Cleanup Functions
React 19 also introduces ref cleanup functions. When you pass a callback ref, you can now return a cleanup function that React will run when the component unmounts. Be aware that TypeScript will now reject implicit returns in these callbacks to prevent accidental bugs. Keep a close eye on your type checks during the migration.
Conclusion
Cleaning up technical debt isn’t always about adding new features or optimizing performance; sometimes, the best commit is the one that removes unnecessary boilerplate. By simplifying how we handle refs, React 19 makes our code more readable, easier to type, and significantly more maintainable.
Are you planning to migrate your component libraries to React 19 soon, or are you waiting for the ecosystem to mature further? Let me know your thoughts in the comments.