Skip to the solution
MediumFrontend8 min read

What are ng-container and ng-template?

524 views

The problem

Question presented to candidate: "You will see <ng-container> and <ng-template> all over Angular codebases. What is each one, what ends up in the DOM, and when would you reach for them?"

What a strong answer should cover:

  • ng-container is a logical grouping element: its children render, but no element is created for it (Angular leaves only a comment anchor).
  • ng-template is a template definition: its content does not render by itself; it is a TemplateRef that something must instantiate (ngTemplateOutlet, a structural directive, ViewContainerRef.createEmbeddedView).
  • Typical ng-container uses: hosting a directive without an extra element (for example *ngTemplateOutlet), grouping siblings where a wrapper would break HTML or CSS (inside <tbody>, <select>, flex/grid).
  • Typical ng-template uses: reusable fragments, templates passed to child components, the else branch of the old *ngIf, custom structural directives.
  • The * prefix is sugar for wrapping an element in an ng-template; only one * is allowed per element, which is why ng-container was used to stack them.
  • With built-in control flow (@if, @for), many old ng-container / ng-template wrappers are no longer needed.

Clarifying questions expected:

  • "Are we on built-in control flow, or still on structural directives?"

Code / implementation expected: Yes β€” a template using both, ideally with ngTemplateOutlet.

  • ng-container
  • ng-template

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

8 min read Β· 9 sections

Read the code

Angularng-container grouping table rows and ng-template as a reusable badge
import { Component, signal } from "@angular/core";
import { NgTemplateOutlet } from "@angular/common";

type Invoice = { id: number; customer: string; lines: string[]; overdue: boolean };

@Component({
  selector: "app-root",
  imports: [NgTemplateOutlet],
  template: `
    <!-- ng-template: a blueprint. Nothing renders until someone stamps it out. -->
    <ng-template #badge let-label>
      <span class="badge">{{ label }}</span>
    </ng-template>

    <table>
      <tbody>
        @for (inv of invoices(); track inv.id) {
          <!-- ng-container: groups the rows of one invoice but renders no element, so tbody stays valid -->
          <ng-container>
            <tr>
              <td>#{{ inv.id }} {{ inv.customer }}</td>
              <td>
                <ng-container *ngTemplateOutlet="badge; context: { $implicit: inv.overdue ? 'OVERDUE' : 'paid' }" />
              </td>
            </tr>
            @if (expanded()) {
              <tr><td colspan="2">{{ inv.lines.join(", ") }}</td></tr>
            }
          </ng-container>
        }
      </tbody>
    </table>
    <button (click)="expanded.set(!expanded())">{{ expanded() ? "Hide" : "Show" }} lines</button>
  `,
})
export class AppComponent {
  expanded = signal(false);
  invoices = signal<Invoice[]>([
    { id: 101, customer: "Acme", lines: ["Hosting", "Support"], overdue: true },
    { id: 102, customer: "Globex", lines: ["Licence"], overdue: false },
  ]);
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 53 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextMedium

What is ngTemplateOutlet?

Continue