ViewChild and ContentChild in Angular
ViewChild and ContentChild
@ViewChild and @ContentChild are decorators that give you programmatic access to child elements, components, or directives in your template.
@ViewChild — Access Template Elements
Access elements defined in the component's own template:
typescript
@Component({
template: \`
<input #nameInput type="text">
<app-chart #chart [data]="chartData"></app-chart>
<button (click)="focusInput()">Focus</button>
\`
})
export class MyComponent implements AfterViewInit {
@ViewChild('nameInput') inputEl!: ElementRef<HTMLInputElement>;
@ViewChild('chart') chartComponent!: ChartComponent;
ngAfterViewInit() {
// Available after view init
this.inputEl.nativeElement.focus();
this.chartComponent.refresh();
}
focusInput() {
this.inputEl.nativeElement.focus();
}
}@ViewChildren — Multiple Elements
typescript
@Component({
template: \`
<app-tab *ngFor="let tab of tabs" [title]="tab.title">
{{ tab.content }}
</app-tab>
\`
})
export class TabsComponent implements AfterViewInit {
@ViewChildren(TabComponent) tabComponents!: QueryList<TabComponent>;
ngAfterViewInit() {
this.tabComponents.forEach(tab => console.log(tab.title));
// React to changes (when *ngFor adds/removes items)
this.tabComponents.changes.subscribe(tabs => {
console.log('Tabs changed:', tabs.length);
});
}
}@ContentChild — Access Projected Content
Access elements projected into the component via <ng-content>:
typescript
@Component({
selector: 'app-panel',
template: \`
<div class="panel">
<ng-content></ng-content>
</div>
\`
})
export class PanelComponent implements AfterContentInit {
@ContentChild('panelTitle') titleEl!: ElementRef;
@ContentChild(ButtonComponent) button!: ButtonComponent;
ngAfterContentInit() {
// Available after content init
console.log(this.titleEl?.nativeElement.textContent);
}
}html
<!-- Parent template -->
<app-panel>
<h2 #panelTitle>My Panel</h2>
<app-button>Click me</app-button>
</app-panel>ViewChild vs ContentChild
| Feature | @ViewChild | @ContentChild |
|---|---|---|
| Accesses | Component's own template | Projected content (ng-content) |
| Lifecycle | ngAfterViewInit | ngAfterContentInit |
| Multiple | @ViewChildren | @ContentChildren |
| Defined in | The component's template | Parent's template (projected) |
Signal Queries (Angular 17+)
typescript
@Component({ /* ... */ })
export class MyComponent {
// Signal-based queries (modern)
nameInput = viewChild.required<ElementRef>('nameInput');
chart = viewChild(ChartComponent);
tabs = viewChildren(TabComponent);
// Content queries
title = contentChild<ElementRef>('title');
buttons = contentChildren(ButtonComponent);
}Read Option
typescript
// Read as ElementRef instead of component instance
@ViewChild('myComp', { read: ElementRef }) el!: ElementRef;
// Read the ViewContainerRef (for dynamic components)
@ViewChild('container', { read: ViewContainerRef }) container!: ViewContainerRef;Important:
@ViewChild accesses elements in the component's own template (available in ngAfterViewInit). @ContentChild accesses projected content (available in ngAfterContentInit). In Angular 17+, prefer signal-based queries (viewChild(), contentChild()). Use QueryList.changes to react to dynamic content changes.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.