Sometimes binding alone isn't enough, you need direct programmatic access to a child element, component, or directive instance. This lesson covers @ViewChild and @ContentChild and their plural forms.
What Are ViewChild and ContentChild?
@ViewChild gives a component direct access to an element, directive, or child component defined in its own template. @ContentChild gives access to content that was projected into the component from its parent via <ng-content>.
Both are available once the relevant part of the component lifecycle finishes: @ViewChild after ngAfterViewInit, and @ContentChild after ngAfterContentInit.
Query by a template reference variable name (string) or by a component/directive class.
@ViewChild/@ContentChild return a single match; the plural forms return a QueryList.
Values are undefined until the corresponding lifecycle hook (ngAfterViewInit/ngAfterContentInit) has run.
The modern signal-based equivalents are viewChild(), viewChildren(), contentChild(), and contentChildren().
ViewChild/ContentChild Cheatsheet
Classic decorators and their modern signal-based equivalents.
Task
Classic
Modern
Single view child
@ViewChild(Ref)
viewChild(Ref)
Multiple view children
@ViewChildren(Ref)
viewChildren(Ref)
Single projected child
@ContentChild(Ref)
contentChild(Ref)
Multiple projected children
@ContentChildren(Ref)
contentChildren(Ref)
Required (no undefined)
n/a (always optional)
viewChild.required(Ref)
Read value
this.ref.nativeElement
this.ref().nativeElement
Querying a Child Component Instance
Passing a component class (instead of a string) to @ViewChild lets you call public methods or read public properties directly on a specific child component instance.
Here the template reference variable #modal is used directly in the template, avoiding a @ViewChild query entirely for this simple case.
Multiple Matches With ViewChildren
@ViewChildren returns a QueryList, an observable-like collection that updates automatically as matching elements are added or removed, useful for working with dynamic lists of child components.
@ContentChild looks for a match inside content projected into the component from its parent (via <ng-content>), rather than inside the component's own template.
Reading a @ViewChild reference in ngOnInit, before the view (and thus the reference) exists; use ngAfterViewInit instead.
Forgetting the non-null assertion (!) or proper typing, leading to confusing undefined errors at compile time.
Overusing @ViewChild for things that could be solved with simple @Input()/@Output() communication instead.
Not unsubscribing from QueryList.changes when a component using @ViewChildren is destroyed.
Key Takeaways
@ViewChild/@ViewChildren access elements, directives, or components from a component's own template.
@ContentChild/@ContentChildren access content projected in from a parent via <ng-content>.
Values are only available after the relevant lifecycle hook has run, not before.
Modern signal-based equivalents (viewChild(), contentChild(), etc.) integrate directly with Angular signals.
Pro Tip
Reach for @ViewChild/@ContentChild only when binding-based communication (inputs, outputs, services) can't express what you need, they create tighter coupling between parent and child than declarative bindings.
You now understand ViewChild and ContentChild. Next, learn about Content Projection to build flexible, composable components with ng-content.