Component Interaction
Advanced View Hierarchy Management
While template inputs (@Input) and outputs (@Output) handle basic vertical data communication, complex UI components—such as tabs, accordions, modals, and specialized dropdown lists—require tighter programmatic control over their templates and nested children.
To build these advanced structures, modern component frameworks decouple template composition and DOM querying into two advanced layout paradigms:
Content Projection and Element Querying Hooks.
Content Projection (ng-content)
Content Projection is a layout pattern that allows a component to receive an external markup fragment from its parent and inject it directly inside its own private HTML layout template. This is the foundation for building highly reusable wrapper elements like custom cards, modal dialogs, and navigation panels.
1. Single-Slot Projection
By default, placing an open <ng-content></ng-content> tag inside a child component creates a catch-all layout bucket. Any HTML layout or nested component elements placed between the parent opening and closing component tags will project automatically into that exact spot.
HTML
<div class="card-container">
<div class="card-header">System Notice</div>
<div class="card-body">
<ng-content></ng-content>
</div>
</div>
HTML
<app-flexible-card>
<p>Your target follower growth has reached 15,000 users this quarter.</p>
<button>Dismiss Notice</button>
</app-flexible-card>2. Multi-Slot (Named) Projection
When you need to distribute different external HTML fragments into separate, specific positions within the child component layout, you use Multi-Slot Projection. By appending a select attribute selector tag to separate <ng-content> placeholders, you dictate exactly where individual fragments land based on matching CSS classes, tag names, or attributes.
<div class="modal-box"> <header class="modal-title-bar"> <ng-content select="[modal-title]"></ng-content> </header> <section class="modal-main-content"> <ng-content select=".modal-body-text"></ng-content> </section> </div> HTML <app-structured-modal> <h2 modal-title>Confirm Action</h2> <div class="modal-body-text"> <p>Are you sure you want to permanently delete this job post reference model?</p> </div> </app-structured-modal>
Querying the Template Canvas: ViewChild
The @ViewChild decorator (or modern signal-based viewChild primitive) allows a component class to query and obtain a programmatic execution reference to an element or nested component that lives inside its own template layout view.
[Image diagram contrasting ViewChild querying internal component templates with ContentChild querying projected external templates]
Execution Availability Lifespan: Because view compilation must complete entirely before the DOM elements exist, a
ViewChildreference is not immediately available when the component class initializes (ngOnInit). It resolves and becomes safe to interface with during thengAfterViewInitlifecycle hook.
TypeScript
// Child Component Widget (custom-input.component.ts)
import { Component } from '@angular/core';
@Component({
selector: 'app-custom-input',
standalone: true,
template: `<input #textInput type="text" class="styled-input" />`
})
export class CustomInputComponent {
public clearAndFocusField(): void {
console.log('Executing internal input component interaction behavior.');
}
}
TypeScript
// Parent Component querying its view child template (dashboard.component.ts)
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { CustomInputComponent } from './custom-input.component';
@Component({
selector: 'app-dashboard',
standalone: true,
imports: [CustomInputComponent],
template: `
<div #nativeAlert class="alert-box">Action Success</div>
<app-custom-input #formField></app-custom-input>
`
})
export class DashboardComponent implements AfterViewInit {
// Querying a native HTML node wrapped automatically inside an ElementRef container
@ViewChild('nativeAlert') alertBoxElement!: ElementRef<HTMLDivElement>;
// Querying a child component instance type directly to access its public APIs
@ViewChild('formField') formFieldComponent!: CustomInputComponent;
ngAfterViewInit(): void {
// 1. Interfacing directly with native browser DOM properties safely
this.alertBoxElement.nativeElement.style.backgroundColor = '#28a745';
// 2. Executing programmatic methods exposed directly on the nested component
this.formFieldComponent.clearAndFocusField();
}
}Querying Projected Content: ContentChild
The @ContentChild decorator (or modern signal-based contentChild primitive) allows a component to query and look up a reference to an element or component that was projected into its layout from the outside via content projection (ng-content).
Execution Availability Lifespan: Because projected elements are processed and passed down from the parent layout prior to the child's local template resolution, a
ContentChildquery resolves earlier than aViewChild, becoming safe to evaluate during thengAfterContentInitlifecycle hook.
TypeScript
// Tab Component managing projected nodes (tab-panel.component.ts)
import { Component, ContentChild, ElementRef, AfterContentInit } from '@angular/core';
@Component({
selector: 'app-tab-panel',
standalone: true,
template: `
<div class="tab-wrapper">
<div class="projected-content-socket">
<ng-content></ng-content>
</div>
</div>
`
})
export class TabPanelComponent implements AfterContentInit {
// Querying an external template element projected inside by the calling parent layer
@ContentChild('projectedHeader') externalHeaderRef!: ElementRef<HTMLHeadingElement>;
ngAfterContentInit(): void {
if (this.externalHeaderRef) {
console.log('Successfully intercepted projected element node context properties.');
this.externalHeaderRef.nativeElement.classList.add('compiled-tab-title');
}
}
}