Sign in

Build 10x products in minutes by chatting with AI - beyond just a prototype.
In traditional React (preāReact 19), you usedāÆReact.forwardRef to āforwardā a ref from a parent component down to a child (typically a DOM node) when the child was a function component. This allowed the parent to directly manipulate or read the underlying DOM node (or even call methods on a child) without breaking the ādata down, actions upā paradigm. With TypeScript, you can annotate both the ref type and the componentās props for safe, predictable behavior.
Whatās new in React 19?
Starting in React 19, function components now automatically accept the ref prop. In many cases you can simply define your component as a function that accesses props.ref without wrapping it ināÆReact.forwardRef (and Reactās upcoming codemods will automatically update legacy code). Still, if you need to customize the value that is exposed (usingāÆuseImperativeHandle) or if you need compatibility with older React versions, you should continue to useāÆforwardRef.
forwardRef?Fundamentally, forwardRef is a utility that lets you pass a ref from a parent component through a child function component to a specific DOM node or instance. Prior to React 19, function components did not receive a ref because they lacked an instance. Wrapping a component ināÆReact.forwardRef provided a way for the parentās ref to be forwarded to a childās internal element.
In React 19:
<input>), you can now simply accept a ref prop in your function component.useImperativeHandle), wrapping with forwardRef is still required.forwardRef with TypeScriptTraditionally, you would write a function component that accepts a ref as a second parameter using the ForwardRefRenderFunction type:
1import React, { forwardRef, ForwardRefRenderFunction } from 'react'; 2 3interface ButtonProps { 4 onClick: () => void; 5} 6 7const Button: ForwardRefRenderFunction<HTMLButtonElement, ButtonProps> = ({ onClick }, ref) => ( 8 <button ref={ref} onClick={onClick}> 9 Click Me 10 </button> 11); 12 13export default forwardRef(Button);
In this example the ref is typed as HTMLButtonElement and the props are typed via ButtonProps. This pattern ensures that the parent component can interact with the buttonās DOM node in a typeāsafe way.
Now that function components automatically receive the ref as a prop, if your componentās only job is to pass the ref along (for example, directly to an <input> or <button>), you can write:
1import React from 'react'; 2 3interface TextInputProps { 4 placeholder: string; 5 // Note: the ref will now be included in props automatically. 6} 7 8export function TextInput({ placeholder, ref }: TextInputProps & { ref?: React.Ref<HTMLInputElement> }) { 9 // Directly use the ref prop. 10 return <input ref={ref} placeholder={placeholder} />; 11}
Note: If you need to use hooks such as
useImperativeHandleto expose custom methods, then you must continue to wrap your component inReact.forwardRef. In that case the code remains similar to the āold way.ā
forwardRefIf you need to expose a childās DOM node (or a custom handle) to the parent, hereās an example using forwardRef with TypeScript:
1import React, { forwardRef, useImperativeHandle, useRef, ChangeEvent } from 'react'; 2 3interface ChildProps { 4 label: string; 5} 6 7const ChildComponent = forwardRef<HTMLInputElement, ChildProps>(({ label }, ref) => { 8 const inputRef = useRef<HTMLInputElement>(null); 9 10 // Expose only the focus method. 11 useImperativeHandle(ref, () => ({ 12 focus: () => { 13 inputRef.current?.focus(); 14 } 15 })); 16 17 return ( 18 <div> 19 <label>{label}</label> 20 <input ref={inputRef} type="text" /> 21 </div> 22 ); 23}); 24 25export default ChildComponent;
In this setup, the parent can now call the focus method on the childās input element. This pattern is useful when you want to encapsulate internal behavior while still allowing the parent to control certain actions.
Hereās how a parent component can use the above child component:
1import React, { useRef } from 'react'; 2import ChildComponent from './ChildComponent'; 3 4const ParentComponent = () => { 5 // Create a ref that expects an object with a focus() method. 6 const inputRef = useRef<{ focus: () => void }>(null); 7 8 const focusInput = () => { 9 inputRef.current?.focus(); 10 }; 11 12 return ( 13 <div> 14 <ChildComponent ref={inputRef} label="Your Name" /> 15 <button onClick={focusInput}>Focus Input</button> 16 </div> 17 ); 18}; 19 20export default ParentComponent;
This parent uses the ref to trigger the focus behavior exposed by the child component.
When more control is needed, you can expose a subset of a child componentās functionality. For example, using useImperativeHandle (as shown above) allows you to expose only the methods you choose, keeping internal details private.
forwardRefWhen using TypeScript, itās important to type both the ref and the componentās props. Hereās another example:
1import React, { forwardRef } from 'react'; 2 3interface ButtonProps { 4 label: string; 5} 6 7interface ButtonRef { 8 focus: () => void; 9} 10 11const Button = forwardRef<ButtonRef, ButtonProps>(({ label }, ref) => { 12 // In this example, the focus is handled internally. 13 return ( 14 <button ref={ref}> 15 {label} 16 </button> 17 ); 18}); 19 20export default Button;
This ensures that the parentās ref is correctly typed to only expose the defined methods.
forwardRefLegacy Support & Custom Imperative Handles:
If you are writing a component library that must work with React versions prior to 19 or you need to expose custom methods (e.g. using useImperativeHandle), continue using forwardRef.
Simple DOM Ref Forwarding in React 19:
For components that simply need to pass the ref to a DOM element without modification, you can now take advantage of the new ref-as-a-prop behavior in React 19. This simplifies your code and reduces boilerplate.
Prefer āRef as a Propā in New Projects:
In React 19 projects, if your component only needs to forward the ref without any transformation, define it as a regular function component and access the ref from props.
Use useImperativeHandle Only When Necessary:
Only expose methods beyond the raw DOM node if required by your use case.
Keep Ref Usage Focused:
Refs should be used for imperative tasks (like focusing, scrolling, or triggering animations) rather than for driving rendering logic. For stateful logic that affects rendering, use state or context.
With React 19, the landscape of ref handling has changed. For many common cases, you no longer need to wrap your components in forwardRef just to pass a ref to a DOM nodeāfunction components now receive the ref as a prop automatically. However, if you need to customize what is exposed to the parent (for example, by using useImperativeHandle), or if you need backward compatibility, using forwardRef remains the recommended approach.
By following the updated practices above and leveraging TypeScript for strong type safety, you can create robust, reusable components that work seamlessly in both legacy and modern React environments.
Happy coding!