ng-template & ng-container

Render Markup Lazily or Group Without a Wrapper

ng-template & ng-container

The `<ng-template>` element is a chunk of markup you instantiate later, and `<ng-container>` groups children without adding a real DOM element.

4 min read Level 3/5 #angular#templates#ng-template
What you'll learn
  • Define an `<ng-template>` and render it on demand
  • Use `<ng-container>` to avoid wrapper divs
  • Accept an `<ng-template>` as a TemplateRef input

<ng-template> and <ng-container> are two special elements Angular provides for shaping templates without disturbing the rendered DOM.

ng-container — Group Without a Wrapper

Sometimes you want to apply structural logic without adding a <div> that breaks your layout. <ng-container> is invisible at runtime:

@if (user(); as u) {
  <ng-container>
    <h2>{{ u.name }}</h2>
    <p>{{ u.bio }}</p>
  </ng-container>
}

The two children render side by side as siblings — no wrapper element appears in the DOM.

ng-template — Markup You Decide When to Render

<ng-template> defines markup that is not rendered immediately. You can render it later by reference:

<ng-template #greeting let-name="name">
  <p>Hello {{ name }}!</p>
</ng-template>

<ng-container *ngTemplateOutlet="greeting; context: { name: 'Ada' }">
</ng-container>

The let-name syntax declares a template input variable, fed by the context object.

Accepting a Template as an Input

A reusable component can accept an <ng-template> from its parent and render it as a slot. This is how libraries expose customizable lists, tables, and modals:

import { Component, contentChild, TemplateRef } from '@angular/core';
import { NgTemplateOutlet } from '@angular/common';

@Component({
  selector: 'app-list',
  standalone: true,
  imports: [NgTemplateOutlet],
  template: `
    @for (item of items; track item.id) {
      <ng-container
        *ngTemplateOutlet="rowTpl(); context: { $implicit: item }">
      </ng-container>
    }
  `,
})
export class ListComponent {
  items = [{ id: 1, name: 'Ada' }, { id: 2, name: 'Grace' }];
  rowTpl = contentChild.required(TemplateRef);
}

The parent uses it like this:

<app-list>
  <ng-template let-item>
    <strong>{{ item.name }}</strong>
  </ng-template>
</app-list>

When to Use Which

  • Need to group children but don’t want a <div>? <ng-container>.
  • Need markup that renders zero, one, or many times later? <ng-template>.
  • Need a reusable slot in a library component? Accept a TemplateRef.
Inputs →