When I first explored template handling and dynamic content in Angular, I was struck by how many directives—ng-template, ng-container, and ng-content—seemed to overlap. They look quite alike at first glance, yet each carries its own distinct set of features and practical scenarios.
Below, I’ll walk through different situations where ng-template, ng-container, and ng-content shine, using concrete examples to highlight when each directive is the right choice. To start, here’s a quick breakdown of each:
ng-templatelets you declare a template block that you can reuse as many times as needed inside an Angular component.ng-containeris meant for grouping elements without introducing extra nodes into the resulting DOM.ng-contenthandles the rendering of content supplied by a parent component.
ng-template
ng-template defines a template block that can serve as the basis for rendering content on demand. It gives you a way to write HTML that you can reutilize across multiple locations within a single component.
A typical scenario is using ng-template alongside ngIf or ngSwitch to display conditional content.
<ng-template #myTemplate>
<div *ngIf="hasBalance">
<p>Your amount is 5000€.</p>
</div>
<div *ngIf="!hasBalance">
<p>Sorry, no balance.</p>
</div>
</ng-template>
Here, the template block holds two div elements, each governed by an *ngIf directive. Depending on the value of hasBalance, one of these div elements will be shown.
That same template block can be referenced in several places inside the component via an ng-container element:
<ng-container *ngTemplateOutlet="myTemplate"></ng-container>
ng-container
ng-container enables grouping of elements without inserting any extra nodes into the DOM. It pairs well with structural directives such as *ngIf, *ngFor, and *ngSwitch.
A frequent use case is applying a structural directive to multiple elements at once, without needing a wrapper HTML element. Consider this:
<div *ngIf="hasBalance">
<p>Your amount is 5000€.</p>
</div>
<div *ngIf="!hasBalance">
<p>Sorry, no balance.</p>
</div>
In that snippet, the two div elements each use *ngIf separately. However, if the same *ngIf condition were meant to control both, an extra wrapper tag would normally be required:
<div *ngIf="activeSession">
<div *ngIf="hasBalance">
<p>Your amount is 5000€.</p>
</div>
<div *ngIf="!hasBalance">
<p>Sorry, no balance.</p>
</div>
</div>
That additional div adds no real value. An ng-container can serve the same purpose—grouping those div elements—without producing any tag in the output:
<ng-container *ngIf="activeSession">
<div *ngIf="hasBalance">
<p>Your amount is 5000€.</p>
</div>
<div *ngIf="!hasBalance">
<p>Sorry, no balance.</p>
</div>
</ng-container>
Here, the ng-container bundles the div elements together with no extra HTML node in the DOM.
ng-content
ng-content offers a straightforward mechanism for rendering content that arrives from a parent component. It lets a parent component inject arbitrary markup into a child component’s view.
A classic example is building a reusable component designed to display different content depending on the context. For instance:
@Component({
selector: 'app-alert',
template: `
<div class="alert alert-{{type}}">
<ng-content></ng-content>
</div>
`
})
export class AlertComponent {
@Input() type: string;
}
Here, an AlertComponent receives a type input and relies on ng-content to project whatever content the parent passes in. The parent component can then use it like this:
<app-alert type="success">
<p>Success!</p>
</app-alert>
<app-alert type="danger">
<p>Something went wrong!</p>
</app-alert>
In this setup, AlertComponent is used to show both success and error messages. Whatever is placed inside the component tag gets rendered at the ng-content location in the template.
Conclusion
All three—ng-template, ng-container, and ng-content—are frequently used directives in Angular templates. They might seem interchangeable on the surface, but they each fulfill a specific role.
The examples and scenarios above should give you a clearer sense of when and how to apply each directive effectively.
Photo by Kelly Sikkema on Unsplash
