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 Input component that a form can focus on validation errors.

Code compare

React
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>    </>  );}
React
// 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:

Angular
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

ReactAngular
ref prop (React 19)viewChild(ChildComponent)
forwardRef (legacy)—
Ref to child's inner elementChild exposes an ElementRef or method