ng-template, ng-content, and ng-container

Understand how Angular uses ng-template for reusable template fragments, ng-content for content projection, and ng-container for grouping template logic without adding extra DOM elements.

Lesson content

Overview Angular provides ng-template , ng-content , and ng-container for building flexible and reusable templates. Element Main Purpose ng-template Defines a template fragment that is not rendered immediately ng-content Projects content from a parent into a child component ng-container Groups template logic without creating an extra DOM element 1. ng-template ng-template defines a block of HTML that Angular does not render immediately. Angular renders it only when another directive or API creates a view from that template. Basic Example <ng-template #loadingTemplate> <p>Loading data...</p> </ng-template> This template exists in Angular's template structure, but it does not appear in the DOM by itself. Template Rendering Flow ng-template Defined ↓ Not Rendered Initially ↓ Directive or Code Requests It ↓ Angular Creates Embedded View ↓ Content Appears in DOM Using ng-template with ngTemplateOutlet Use ngTemplateOutlet to render a template fragment. import { Component } from '@angular/core'; import { NgTemplateOutlet } from '@angular/common'; @Component({ selector: 'app-message', standalone: true, imports: [ NgTemplateOutlet ], template: ` <ng-template #messageTemplate> <p>Welcome to Angular</p> </ng-template> <ng-container [ngTemplateOutlet]="messageTemplate"> </ng-container> ` }) export class MessageComponent {} Passing Context to ng-template A template can receive values through a context object. <ng-template #userTemplate let-user let-position="index"> <p> {{ position + 1 }}. {{ user.name }} </p> </ng-template> <ng-container [ngTemplateOutlet]="userTemplate" [ngTemplateOutletContext]="{ $implicit: selectedUser, index: 0 }"> </ng-container> Context Explanation Syntax Meaning $implicit Default context value let-user Reads the $implicit value let-position="index" Reads the named index value Accessing TemplateRef Angular represents an ng-template as a TemplateRef . import { Component, TemplateRef, viewChild } from '@angular/core'; @Component({ selector: 'app-dialog', standalone: true, template: ` <ng-template #dialogTemplate> <h2>Delete Item?</h2> </ng-template> ` }) export class DialogComponent { dialogTemplate = viewChild.required<TemplateRef<unknown>>( 'dialogTemplate' ); } TemplateRef is commonly used for dialogs, overlays, tables, and reusable layout templates. 2. ng-content ng-content is used for content projection. It allows a parent component to provide markup that a child component displays inside its own template. Real-Life Example Reusable Card Component ↓ Parent Provides: Title Body Buttons ↓ Card Displays Projected Content Basic Content Projection Child component: import { Component } from '@angular/core'; @Component({ selector: 'app-card', standalone: true, template: ` <section class="card"> <ng-content /> </section> ` }) export class CardComponent {} Parent usage: <app-card> <h2>User Profile</h2> <p>Ajay is an Angular developer.</p> </app-card> Rendered Result <section class="card"> <h2>User Profile</h2> <p>Ajay is an Angular developer.</p> </section> Multiple Content Projection Slots Use the select attribute to create multiple projection areas. Child Component @Component({ selector: 'app-panel', standalone: true, template: ` <section class="panel"> <header> <ng-content select="[panel-title]" /> </header> <main> <ng-content select="[panel-body]" /> </main> <footer> <ng-content select="[panel-actions]" /> </footer> </section> ` }) export class PanelComponent {} Parent Usage <app-panel> <h2 panel-title> Account Details </h2> <p panel-body> User account information </p> <button panel-actions> Save </button> </app-panel> Projection Flow Parent Markup ↓ Angular Matches select Rules ↓ Title → Header Slot Body → Main Slot Button → Footer Slot Fallback Content Content placed inside ng-content can act as fallback content when the parent provides nothing for that slot. <ng-content select="[panel-title]"> <h2>Default Title</h2> </ng-content> Important ng-content Rule ng-content is processed while Angular compiles the component template. Do not try to dynamically add or remove ng-content itself using control-flow blocks. Instead, conditionally wrap projected content or use ng-template for dynamic rendering. Content Projection vs Inputs Inputs ng-content Pass data Pass markup Good for strings, numbers, and objects Good for HTML and components Child controls rendering Parent controls projected structure input() or @Input() ng-content 3. ng-container ng-container groups Angular template logic without adding a real HTML element to the DOM. Why Do We Need ng-container? Sometimes Angular needs a wrapper for conditions, loops, templates, or directives, but an extra HTML element would break styling or layout. Without ng-container <div> <p>Product One</p> <p>Product Two</p> </div> The extra div becomes part of the DOM. With ng-container <ng-container> <p>Product One</p> <p>Product Two</p> </ng-container> Rendered DOM <p>Product One</p> <p>Product Two</p> No ng-container element appears in the final DOM. ng-container with Control Flow @if (isLoggedIn) { <ng-container> <h2>Welcome</h2> <p>You are logged in.</p> </ng-container> } In many cases, modern control-flow blocks already support multiple elements, so an extra ng-container may not be required. ng-container with ngTemplateOutlet <ng-template #emptyState> <p>No products found</p> </ng-template> <ng-container [ngTemplateOutlet]="emptyState"> </ng-container> ng-container with Directives <ng-container *ngIf="isAdmin"> <button>Delete User</button> <button>Block User</button> </ng-container> For new templates, prefer modern control flow: @if (isAdmin) { <button>Delete User</button> <button>Block User</button> } Complete Example Reusable List Component import { Component, input, TemplateRef } from '@angular/core'; import { NgTemplateOutlet } from '@angular/common'; @Component({ selector: 'app-list', standalone: true, imports: [ NgTemplateOutlet ], template: ` <section> <header> <ng-content select="[list-title]" /> </header> @for (item of items(); track item.id) { <ng-container [ngTemplateOutlet]="itemTemplate()" [ngTemplateOutletContext]="{ $implicit: item }"> </ng-container> } @empty { <ng-content select="[empty-state]" /> } </section> ` }) export class ListComponent<T extends { id: number }> { items = input.required<T[]>(); itemTemplate = input.required<TemplateRef<{ $implicit: T }>>(); } Parent Usage <ng-template #productTemplate let-product> <article> <h3>{{ product.name }}</h3> <p>{{ product.price | currency }}</p> </article> </ng-template> <app-list [items]="products" [itemTemplate]="productTemplate"> <h2 list-title> Products </h2> <p empty-state> No products available </p> </app-list> ng-template vs ng-content vs ng-container Feature ng-template ng-content ng-container Main purpose Define reusable template content Project parent markup Group template logic Rendered automatically No Displays projected content Its children may render Creates DOM element No No wrapper element No Can receive context Yes No template context object No Typical use Dynamic templates and fallback views Cards, dialogs, panels, and layouts Conditions, outlets, and grouping Common Mistakes 1. Expecting ng-template to Render Automatically <ng-template> <p>Hello</p> </ng-template> This does not render by itself. 2. Using ng-content to Pass Data Use inputs to pass data and ng-content to pass markup. 3. Adding Unnecessary Wrapper Elements Use ng-container when a logical wrapper is required but a real DOM element is not. 4. Overusing TemplateRef Prefer normal inputs and child components when the template does not need to be customizable. 5. Mutating Projected Content The parent owns projected content. The child should avoid depending too heavily on its internal structure. Best Practices Use ng-template for reusable or dynamically rendered template fragments Use ng-content when the parent should control the child component's inner markup Use ng-container to avoid unnecessary DOM wrappers Use multiple projection slots only when they improve component clarity Use inputs for data and content projection for markup Keep template context objects strongly typed where possible Prefer modern control-flow blocks for conditions and loops Avoid making reusable components unnecessarily complex Interview Questions What is ng-template? ng-template defines a template fragment that Angular does not render immediately. Angular can later create an embedded view from it. What is ng-content? ng-content is a content-projection placeholder that displays markup supplied by a parent component. What is ng-container? ng-container groups Angular template logic without creating an additional HTML element in the DOM. What is TemplateRef? TemplateRef is Angular's runtime representation of an ng-template . What is content projection? Content projection is the process of inserting parent-provided markup into a child component's ng-content placeholders. How do you create multiple projection slots? Use the select attribute on different ng-content elements. Does ng-container appear in the DOM? No. It is a logical Angular grouping element and does not create a rendered wrapper element. What is the difference between ng-template and ng-container? ng-template defines content that is not rendered until instantiated. ng-container groups content that can render normally without adding a DOM element. Key Point Use ng-template to define a view, ng-content to receive a view, and ng-container to group a view without creating extra HTML. Easy Formula ng-template = Define Hidden Template ng-content = Receive Parent Markup ng-container = Group Without DOM Element Parent Content ↓ ng-content ↓ Reusable Child Layout ng-template ↓ TemplateRef ↓ ngTemplateOutlet ↓ Rendered Embedded View