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.
@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.
@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
1. In which lifecycle hook does a @ViewChild-decorated property first reliably have a resolved value (without static: true)?
2. What does @ContentChild query, as opposed to @ViewChild?
3. What type does @ViewChildren (the plural form) return?
4. Which lifecycle hook resolves earlier: ngAfterContentInit or ngAfterViewInit?
5. What is the signal-based alternative to @ViewChild introduced in Angular 17.2+?
Was this page helpful?
You May Also Like
Content Projection with ng-content
Learn how ng-content lets components accept and render externally-provided markup, enabling flexible, composable UI patterns like cards, modals, and layouts.
Input and Output Decorators
Understand how @Input() and @Output() enable parent-child component communication in Angular, including binding syntax, EventEmitter, and input transforms.
Introduction to Signals
Understand Angular Signals — the reactive primitive that wraps a value and notifies dependents on change, forming the foundation of Angular's modern change-detection model.
Anatomy of a Component
A close look at the parts that make up an Angular component — the decorator metadata, class body, template, and styles — and how they fit together.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics