100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
TypeScript

ViewChild and ContentChild

Learn how @ViewChild/@ViewChildren and @ContentChild/@ContentChildren let a component query and programmatically interact with elements in its own template or projected content.

Component CommunicationIntermediate9 min readJul 9, 2026
Analogies

ViewChild and ContentChild

@ViewChild and @ContentChild are decorators that let a component class obtain a direct programmatic reference to an element, directive, or child component instance, rather than only interacting with it via template bindings. @ViewChild queries the component's own template — the view Angular renders for it — while @ContentChild queries content that was projected into the component from its parent via ng-content. Their plural counterparts, @ViewChildren and @ContentChildren, return a QueryList instead of a single reference, for querying multiple matches, and QueryList exposes a .changes Observable that emits whenever the matched set of elements changes, such as items being added or removed from an *ngFor/@for.

🏏

Cricket analogy: @ViewChild getting a direct reference to your own template's element is like a captain having a direct radio line to their own team's wicketkeeper, while @ViewChildren's QueryList changes Observable is like a manager getting notified every time a substitute enters or leaves the field.

@ViewChild: Querying a Component's Own Template

@ViewChild accepts either a template reference variable string (matching a #ref in the template), a component/directive class type, or a string CSS-like selector, and assigns the matched instance — an ElementRef, a component instance, or a directive instance — to the decorated property. A critical detail is timing: view queries are not resolved until after Angular has initialized the component's view, so @ViewChild-decorated properties are undefined in the constructor and even in ngOnInit; you must read them in the ngAfterViewInit lifecycle hook, or, for static content that never changes based on structural directives, opt into { static: true } to have it resolved earlier, during ngOnInit.

🏏

Cricket analogy: @ViewChild resolving only after ngAfterViewInit is like a new stadium's electronic scoreboard not being wired up and readable until after the ground's full setup is complete, so you can't check its display during the pre-match pitch inspection.

typescript
@Component({
  selector: 'app-search-box',
  standalone: true,
  template: `<input #searchInput type="text" placeholder="Search…" />`
})
export class SearchBoxComponent implements AfterViewInit {
  @ViewChild('searchInput') searchInput!: ElementRef<HTMLInputElement>;

  ngAfterViewInit(): void {
    this.searchInput.nativeElement.focus();
  }
}

@ContentChild: Querying Projected Content

@ContentChild works analogously but targets content projected into the component via ng-content from the parent, rather than the component's own internal template. Because projected content isn't available until Angular has processed the parent's bindings into the child, @ContentChild-decorated properties resolve in ngAfterContentInit, one lifecycle phase earlier than ngAfterViewInit's view-query resolution — content is composed before the component's own view finishes initializing. A common use case is a wrapper component that needs to detect or coordinate with a specific projected child, such as a TabsComponent finding all projected TabComponent instances to manage which one is active.

🏏

Cricket analogy: A TabsComponent using @ContentChild to find projected TabComponent instances is like a captain checking the projected list of specialist bowlers handed to them by the selectors before the toss, resolving even before the field placements (the view) are finalized.

typescript
@Component({
  selector: 'app-tabs',
  standalone: true,
  template: `
    <div class="tab-headers">
      @for (tab of tabs; track tab.title) {
        <button (click)="select(tab)">{{ tab.title }}</button>
      }
    </div>
    <ng-content />
  `
})
export class TabsComponent implements AfterContentInit {
  @ContentChildren(TabComponent) tabQueryList!: QueryList<TabComponent>;
  tabs: TabComponent[] = [];

  ngAfterContentInit(): void {
    this.tabs = this.tabQueryList.toArray();
    if (this.tabs.length) this.select(this.tabs[0]);
  }

  select(tab: TabComponent): void {
    this.tabs.forEach(t => (t.active = t === tab));
  }
}

As of Angular 17.2/17.3, signal-based equivalents viewChild(), viewChildren(), contentChild(), and contentChildren() exist as functions returning Signal<T | undefined> or Signal<ReadonlyArray<T>>. These resolve reactively without the ngAfterViewInit/ngAfterContentInit timing dance — the signal simply reflects 'not yet available' as undefined until the view/content is ready, and consumers can react via computed()/effect() instead of manually implementing lifecycle interfaces.

A very common beginner mistake is trying to read a @ViewChild-decorated property inside ngOnInit — it will be undefined there because view children are resolved after view initialization, not before. Similarly, using { static: true } incorrectly on a @ViewChild that's inside a structural directive like @if/*ngIf can cause the query to resolve to undefined at the wrong time, since 'static' content must exist regardless of any conditional rendering.

  • @ViewChild/@ViewChildren query elements, directives, or components within the component's own template.
  • @ContentChild/@ContentChildren query content projected into the component from its parent via ng-content.
  • @ViewChild resolves in ngAfterViewInit (or ngOnInit with { static: true }); it is undefined in the constructor.
  • @ContentChild resolves in ngAfterContentInit, one phase earlier than view children resolve.
  • The plural forms return a QueryList, which exposes a .changes Observable that emits when the matched set updates.
  • Signal-based viewChild()/contentChild() functions (Angular 17.2+) offer a simpler, reactive alternative to the decorator + lifecycle-hook pattern.

Practice what you learned

Was this page helpful?

Topics covered

#TypeScript#AngularStudyNotes#WebDevelopment#ViewChildAndContentChild#ViewChild#ContentChild#Querying#Component#StudyNotes#SkillVeris