Working with Refs & PortalsEntry 3 of 6
Passing Refs to Child Components
Letting a parent attach a ref to a DOM element that lives inside a child component.
Notes
In React 19, ref is a regular prop for function components. The child receives it like any other prop and places it on the element it wants to expose.
Before React 19, this required wrapping the child in forwardRef. You'll still see it in existing code and in many course examples; it works but is no longer needed.
What / Why / When
- What
Forwarding a ref through a component.
- Why
Reusable wrappers (inputs, buttons, dialogs) must still let parents focus or measure the underlying element.
- When
A parent needs direct DOM access to an element rendered by a child.
- Use case
A custom
Inputcomponent that a form can focus on validation errors.
Code compare
import { useRef, type ComponentProps } from "react";// React 19: ref arrives as a normal prop (included in ComponentProps<'input'>)export function Input({ ref, ...rest }: ComponentProps<"input">) { return <input ref={ref} className="input" {...rest} />;}export function Form() { const emailRef = useRef<HTMLInputElement>(null); return ( <> <Input ref={emailRef} type="email" /> <button onClick={() => emailRef.current?.focus()}>Focus email</button> </> );}// Legacy (React 18 and earlier): forwardRefimport { forwardRef, type ComponentProps } from "react";export const LegacyInput = forwardRef<HTMLInputElement, ComponentProps<"input">>((props, ref) => ( <input ref={ref} {...props} />));A parent can't reach into a child's template. It queries the child component instance and uses what the child makes public:
import { Component, ElementRef, viewChild } from "@angular/core";@Component({ selector: "app-input", template: `<input #field class="input" />`,})export class InputComponent { field = viewChild.required<ElementRef<HTMLInputElement>>("field"); // public: parent may use it}@Component({ selector: "app-form", imports: [InputComponent], template: ` <app-input /> <button (click)="focusEmail()">Focus email</button> `,})export class FormComponent { private emailInput = viewChild.required(InputComponent); // query by component type focusEmail() { this.emailInput().field().nativeElement.focus(); }}If the child uses the attribute selector pattern (input[appInput], see React Essentials, Entry 5), the host is the native element, and the parent can query its ElementRef directly.
Differences and gotchas
- React forwards a ref to a specific element the child chooses. Angular hands the parent the whole component instance.
- Exposing raw DOM access couples the parent to the child's markup. Prefer exposing methods (Entry 4).
Quick reference
| React | Angular |
|---|---|
ref prop (React 19) | viewChild(ChildComponent) |
forwardRef (legacy) | — |
| Ref to child's inner element | Child exposes an ElementRef or method |