forwardRef ist eine React-API, die eine Function-Component wickelt und ihr erlaubt, eine ref aus dem Eltern-Aufruf zu empfangen und weiterzureichen. Ohne forwardRef ist die ref-Prop bei Function-Components stumm — React warnt sogar in DevMode. Mit forwardRef wird die Komponente zur „Brücke" und kann die ref an ein internes DOM-Element binden. Wichtig: ab React 19 ist ref eine ganz normale Prop, und forwardRef wird obsolet. Wer auf React 19 setzt, kann direkt ref={...} an Custom-Components übergeben, ohne Wrapper.
Das Problem ohne forwardRef
Bei nativen DOM-Elementen funktioniert ref direkt. Bei eigenen Function-Components nicht — React warnt:
function FancyInput(props) {
return <input className="fancy" {...props} />;
}
function Form() {
const inputRef = useRef(null);
return <FancyInput ref={inputRef} />;
// Warning: Function components cannot be given refs.
}inputRef.current bleibt null. Die ref-Prop wird nicht an das innere <input> weitergereicht.
Lösung mit forwardRef (React 16.3 – 18)
forwardRef wickelt die Komponente und macht den zweiten Parameter ref verfügbar:
import { forwardRef, useRef } from 'react';
const FancyInput = forwardRef(function FancyInput(props, ref) {
return <input className="fancy" ref={ref} {...props} />;
});
function Form() {
const inputRef = useRef(null);
const handleFocus = () => {
inputRef.current.focus();
};
return (
<>
<FancyInput ref={inputRef} />
<button onClick={handleFocus}>Fokussieren</button>
</>
);
}Jetzt zeigt inputRef.current auf das innere <input>-DOM-Element. focus() funktioniert.
Mit TypeScript
import { forwardRef, useRef } from 'react';
type FancyInputProps = {
placeholder?: string;
};
const FancyInput = forwardRef<HTMLInputElement, FancyInputProps>(
function FancyInput(props, ref) {
return <input className="fancy" ref={ref} {...props} />;
}
);
function Form() {
const inputRef = useRef<HTMLInputElement>(null);
// inputRef.current ist HTMLInputElement | null
return <FancyInput ref={inputRef} placeholder="Name" />;
}Generische Typen: erst der Element-Typ (worauf zeigt die ref?), dann der Props-Typ.
React 19 — ref als normale Prop
Ab React 19 ist forwardRef obsolet. Components empfangen ref direkt als Prop:
// React 19+ — kein forwardRef nötig
function FancyInput({ ref, ...props }) {
return <input className="fancy" ref={ref} {...props} />;
}
function Form() {
const inputRef = useRef(null);
return <FancyInput ref={inputRef} placeholder="Name" />;
}Vorteile:
- Keine Doppel-Funktion-Wrapping (
forwardRef(function ...)). - TypeScript-Typing einfacher (ref ist nur eine Prop).
- Konsistenter mit anderen Props.
Migration: einfach forwardRef(...) entfernen und ref zum Props-Destructuring hinzufügen. React-19-Linter helfen dabei.
Mit useImperativeHandle kombinieren
Wenn man nicht das innere DOM-Element nach außen geben will, sondern ein eigenes API (z.B. nur focus() und clear()), kombiniert man forwardRef mit useImperativeHandle:
import { forwardRef, useImperativeHandle, useRef } from 'react';
const FancyInput = forwardRef(function FancyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
focus: () => inputRef.current.focus(),
clear: () => { inputRef.current.value = ''; },
}), []);
return <input ref={inputRef} {...props} />;
});
function Form() {
const fancyRef = useRef(null);
return (
<>
<FancyInput ref={fancyRef} />
<button onClick={() => fancyRef.current.focus()}>Fokus</button>
<button onClick={() => fancyRef.current.clear()}>Leeren</button>
</>
);
}fancyRef.current hat dann nur die Methoden focus und clear — nicht das ganze DOM-Element. Sauberere API, weniger Coupling.
displayName für DevTools
forwardRef-Components zeigen in React DevTools per Default als „ForwardRef" an. Mit displayName lässt sich das anpassen:
const FancyInput = forwardRef(function FancyInput(props, ref) {
return <input ref={ref} {...props} />;
});
FancyInput.displayName = 'FancyInput';In React 19 ist das unnötig — die Komponente hat ohnehin ihren Funktions-Namen.
Besonderheiten
forwardRef ist bis React 18 Pflicht für Component-Refs.
Ohne forwardRef wird die ref-Prop einer Function-Component IGNORIERT — React warnt im Dev-Mode. forwardRef macht ref zum zweiten Parameter der Komponenten-Funktion.
React 19: ref ist eine normale Prop — `forwardRef` obsolet.
Ab React 19 kann jede Function-Component ref direkt aus den Props nehmen. forwardRef bleibt rückwärtskompatibel, ist aber für neuen Code unnötig. Linter erkennen und schlagen die Migration vor.
forwardRef-Component-Signatur: `(props, ref)` statt nur `props`.
Anders als normale Function-Components hat die mit forwardRef gewickelte Funktion ZWEI Parameter. Erst props, dann ref. Beim Destructuring beider muss man das beachten.
ref-Forwarding ans innere Element: `ref={ref}` an den DOM-Knoten.
Innerhalb der gewickelten Komponente muss die empfangene ref an ein echtes DOM-Element (oder eine andere forwardRef-Komponente) weitergegeben werden, damit sie etwas „zeigt". Sonst bleibt sie null.
useImperativeHandle für selektives Component-API.
Statt das ganze DOM nach außen zu geben, exposed man nur ausgewählte Methoden. Klare API, weniger Coupling. Details im useImperativeHandle-Artikel.
TypeScript-Generic: forwardRef.
Erst der Element-Typ (worauf zeigt die ref im Element-Sinn?), dann der Props-Typ. forwardRef<HTMLInputElement, MyInputProps>. In React 19 wird ref typmäßig zu einer normalen Prop und vereinfacht das.
displayName für lesbarere DevTools (pre-React-19).
forwardRef-Components zeigen sich als „ForwardRef" oder „ForwardRef(MyComponent)" in DevTools. MyComponent.displayName = 'MyComponent' macht das sauberer. In React 19 unnötig.
forwardRef NICHT für jeden Component-Use-Case.
Wenn die Komponente nicht imperative gesteuert werden muss (focus, scroll, externes API), braucht sie keine ref. Reine Display-Komponenten brauchen kein forwardRef. Faustregel: erst Bedarf prüfen, dann wrappen.