Skip to content

ngTemplateOutlet

ngTemplateOutlet is a directive that allows you to render a template dynamically in your component. Instead of duplicating HTML, you can define a template once and reuse it multiple times with different data.

  • ✅ Avoid code duplication - Define template once, use many times
  • ✅ Dynamic rendering - Switch between different templates at runtime
  • ✅ Reusable components - Let parent components customize child templates
  • ✅ Conditional layouts - Show different UI based on conditions
  • ✅ List customization - Allow custom item rendering in lists
Use Case Example
Reusable UI patterns Cards, list items, modals
Conditional layouts Different views for logged in/out users
Customizable components Tables, lists with custom row templates
Template switching Different layouts based on viewport or user preference
Avoiding duplication Same HTML structure with different data
import { Component } from '@angular/core';
import { NgTemplateOutlet } from '@angular/common';
@Component({
selector: 'app-template-demo',
standalone: true,
imports: [NgTemplateOutlet],
template: `
<h1>Using ngTemplateOutlet</h1>
<!-- Render the template here -->
<ng-container *ngTemplateOutlet="greetingTemplate"></ng-container>
<!-- Define the template -->
<ng-template #greetingTemplate>
<p>Hello from template!</p>
<p>This can be reused anywhere!</p>
</ng-template>
`
})
export class TemplateDemoComponent {}
@Component({
selector: 'app-album-template',
standalone: true,
imports: [NgTemplateOutlet],
template: `
<!-- Pass data to template using context -->
<ng-container
*ngTemplateOutlet="albumTemplate; context: {
$implicit: album,
index: 0,
isFeatured: true
}">
</ng-container>
<!-- Template receives data with 'let-' variables -->
<ng-template #albumTemplate let-album let-i="index" let-featured="isFeatured">
<div class="album-card">
<p>Album #{{ i }}: {{ album.name }}</p>
<p>Artist: {{ album.artist }}</p>
<span *ngIf="featured" class="badge">⭐ Featured</span>
</div>
</ng-template>
`
})
export class AlbumTemplateComponent {
album = { name: 'Dark Side of the Moon', artist: 'Pink Floyd' };
}
@Component({
selector: 'app-album-cards',
standalone: true,
imports: [NgTemplateOutlet],
template: `
<!-- Use the same template 3 times with different data -->
<ng-container *ngTemplateOutlet="albumTemplate; context: {
name: 'Dark Side of the Moon',
artist: 'Pink Floyd'
}"></ng-container>
<ng-container *ngTemplateOutlet="albumTemplate; context: {
name: 'Abbey Road',
artist: 'The Beatles'
}"></ng-container>
<ng-container *ngTemplateOutlet="albumTemplate; context: {
name: 'Thriller',
artist: 'Michael Jackson'
}"></ng-container>
<!-- Define template once -->
<ng-template #albumTemplate let-name="name" let-artist="artist">
<div class="album-card">
<h2>{{ name }}</h2>
<p>🎤 {{ artist }}</p>
</div>
</ng-template>
`
})
export class AlbumCardsComponent {}

Result: Three album cards with the same structure but different content, without duplicating HTML.

@Component({
selector: 'app-player-view',
standalone: true,
imports: [NgTemplateOutlet],
template: `
<button (click)="isPlaying = !isPlaying">Toggle Playback</button>
<!-- Show different template based on condition -->
<ng-container *ngTemplateOutlet="
isPlaying ? playingTemplate : pausedTemplate
"></ng-container>
<ng-template #playingTemplate>
<div class="now-playing">
<h2>🎵 Now Playing: {{ trackTitle }}</h2>
<p>Your playlist is active</p>
<button (click)="pause()">⏸️ Pause</button>
</div>
</ng-template>
<ng-template #pausedTemplate>
<div class="paused">
<h2>⏸️ Playback Paused</h2>
<button (click)="play()">▶️ Resume</button>
</div>
</ng-template>
`
})
export class PlayerViewComponent {
isPlaying = false;
trackTitle = 'Bohemian Rhapsody';
play() { this.isPlaying = true; }
pause() { this.isPlaying = false; }
}
import { Component, input, TemplateRef } from '@angular/core';
import { NgTemplateOutlet, NgFor } from '@angular/common';
@Component({
selector: 'app-list',
standalone: true,
imports: [NgTemplateOutlet, NgFor],
template: `
<div class="list-container">
<div *ngFor="let item of items(); let i = index" class="list-item">
<!-- Render custom template for each item -->
<ng-container *ngTemplateOutlet="itemTemplate(); context: {
$implicit: item,
index: i
}"></ng-container>
</div>
</div>
`
})
export class ListComponent {
// Signal-based inputs
items = input<any[]>([]);
itemTemplate = input.required<TemplateRef<any>>();
}
@Component({
selector: 'app-data-table',
standalone: true,
imports: [NgTemplateOutlet, NgFor],
template: `
<table>
<thead>
<tr>
<th *ngFor="let column of columns()">{{ column.label }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of data()">
<td *ngFor="let column of columns()">
<!-- Render custom cell template -->
<ng-container *ngTemplateOutlet="
column.cellTemplate;
context: { $implicit: row, column: column }
"></ng-container>
</td>
</tr>
</tbody>
</table>
`
})
export class DataTableComponent {
// Signal-based inputs
columns = input<Column[]>([]);
data = input<any[]>([]);
}
interface Column {
label: string;
cellTemplate: TemplateRef<any>;
}
  • ✅ Use for template reusability - Avoid duplicating HTML
  • ✅ Great for customizable components - Let consumers define how items look
  • ✅ Prefer over complex *ngIf chains - Cleaner than nested conditionals
  • ✅ Use $implicit for primary context value - Simpler syntax
  • ✅ Combine with contentChild() for advanced patterns - More flexible APIs
  • ❌ Don’t overuse - Simple components don’t need templates
  • ❌ Avoid deep nesting - Keep templates shallow and readable
Pattern Use Case
Single template, multiple renders Cards, alerts, modals
Template switching Different layouts based on state
Parent-provided templates Customizable lists, tables, grids
Conditional templates Logged-in/out views, admin/user UI
Template with loops Dynamic list rendering
Approach When to Use
ngTemplateOutlet Need to reuse or switch templates dynamically
ngIf/Else Simple show/hide logic (2 options max)
Component Complex logic, lifecycle hooks needed
ngSwitch Multiple conditions based on single value