ref as a regular prop: goodbye, forwardRef
In React 19, function components receive ref directly in props. And ref callbacks can finally return a cleanup function.
forwardRef was a necessary evil for years: if you wanted your <Input> component to accept a ref, you had to wrap it and live with uglier types. React 19 removes the need — ref is a regular prop for function components.
Before and after
// React 18
const Input = forwardRef<HTMLInputElement, InputProps>(function Input(props, ref) {
return <input ref={ref} {...props} />;
});// React 19
function Input({ ref, ...props }: InputProps & { ref?: React.Ref<HTMLInputElement> }) {
return <input ref={ref} {...props} />;
}The component is a plain function, DevTools show the right name and the types are readable. If you type props with React.ComponentProps<"input">, ref is already included.
forwardRef still works, but it will be deprecated in a future version. There's a codemod for the migration.
Cleanup in ref callbacks
Ref callbacks used to be called with null on unmount. Now you can return a cleanup function — exactly like from an effect:
<div
ref={(node) => {
const observer = new ResizeObserver(([entry]) => {
setWidth(entry.contentRect.width);
});
observer.observe(node);
return () => observer.disconnect();
}}
/>When you return a cleanup, React won't call the callback with null on unmount. TypeScript gotcha: implicit returns (ref={(n) => (instance = n)}) no longer type-check — use curly braces.
When to reach for useImperativeHandle
If you don't want to expose the whole DOM node but only a few methods (focus, scrollToBottom), combine the ref prop with useImperativeHandle(ref, () => ({ … })). It works just like before — minus the wrapping.