patternjavascriptreactModerate
forwardRef pattern for exposing DOM refs from custom components
Viewed 0 times
React 16.3+ for forwardRef; React 19 makes it unnecessary
forwardRefref forwardingDOM refcustom inputparent accessReact 19 ref prop
Error Messages
Problem
Passing a ref prop to a custom function component does nothing by default — React ignores it and throws a warning. The ref only works on host elements (div, input, etc.) or class components. To accept a ref in a function component, you must explicitly forward it.
Solution
Wrap the component with React.forwardRef:
import { forwardRef, useRef } from 'react';
// Custom input that forwards its ref
const FancyInput = forwardRef(function FancyInput(props, ref) {
return (
<div className="fancy-wrapper">
<input ref={ref} {...props} />
</div>
);
});
// Usage: ref now points to the inner <input>
function Form() {
const inputRef = useRef(null);
function focusInput() {
inputRef.current.focus();
}
return (
<>
<FancyInput ref={inputRef} placeholder="Type here" />
<button onClick={focusInput}>Focus</button>
</>
);
}
// In React 19: forwardRef is no longer needed
// ref is passed as a regular prop
function FancyInput({ ref, ...props }) {
return <input ref={ref} {...props} />;
}
import { forwardRef, useRef } from 'react';
// Custom input that forwards its ref
const FancyInput = forwardRef(function FancyInput(props, ref) {
return (
<div className="fancy-wrapper">
<input ref={ref} {...props} />
</div>
);
});
// Usage: ref now points to the inner <input>
function Form() {
const inputRef = useRef(null);
function focusInput() {
inputRef.current.focus();
}
return (
<>
<FancyInput ref={inputRef} placeholder="Type here" />
<button onClick={focusInput}>Focus</button>
</>
);
}
// In React 19: forwardRef is no longer needed
// ref is passed as a regular prop
function FancyInput({ ref, ...props }) {
return <input ref={ref} {...props} />;
}
Why
React treats ref specially — it is not accessible via props. forwardRef is an escape hatch that lets a parent control a DOM node inside a child component. Common uses: focusing inputs, measuring DOM size, integrating with third-party libraries.
Gotchas
- forwardRef component displayName defaults to 'ForwardRef' in DevTools — set displayName explicitly: FancyInput.displayName = 'FancyInput'
- In React 19, ref is a plain prop — forwardRef is a no-op shim kept for compatibility
- Don't forward refs unless the parent genuinely needs DOM access — it breaks encapsulation
- TypeScript: use React.ForwardedRef<HTMLInputElement> as the second argument type
Code Snippets
forwardRef with displayName
const TextInput = forwardRef(function TextInput({ label, ...props }, ref) {
return (
<label>
{label}
<input ref={ref} {...props} />
</label>
);
});
TextInput.displayName = 'TextInput';Context
When a parent component needs to access a DOM node inside a custom child component
Revisions (0)
No revisions yet.