Skip to the solution
MediumFrontend8 min read

What is standard content projection vs. Multi-Slot Content Projection?

1.0k views

The problem

Question presented to candidate: "Design the template of a reusable <app-dialog> with a title area, a body and a footer for buttons. Explain the difference between standard (single-slot) and multi-slot content projection, and how Angular decides which content goes where."

What a strong answer should cover:

  • Single-slot: one <ng-content /> receives everything between the component's tags.
  • Multi-slot: several <ng-content select="...">, each with a CSS-like selector (element, [attribute], .class, or a comma-separated list).
  • Content is placed in slot order, not source order; each node goes to the first matching slot, and the select-less slot is the catch-all default.
  • Content that matches no slot when there is no default slot is silently dropped.
  • Only top-level nodes are matched; ngProjectAs lets an ng-container (or a wrapper) pretend to match a selector. A control flow block with a single root element projects into that element's slot.
  • Each slot can have its own fallback content (v18+).

Clarifying questions expected:

  • "Should the title be required, or should the dialog show a default?"
  • "Are footer actions always buttons, or could teams pass custom components?"

Code / implementation expected: Yes β€” a dialog or card with at least three slots.

  • content-projection

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

AngularA dialog with title, body and footer slots, fallback title and ngProjectAs
import { Component, signal } from "@angular/core";

// Multi-slot projection: each <ng-content select> is a named "slot".
@Component({
  selector: "app-dialog",
  template: `
    <section style="border: 1px solid #888; padding: 8px; margin: 8px 0">
      <header><ng-content select="[dialog-title]">Untitled</ng-content></header>
      <main><ng-content /></main>
      <footer><ng-content select="button, .actions" /></footer>
    </section>
  `,
})
export class DialogComponent {}

@Component({
  selector: "app-root",
  imports: [DialogComponent],
  template: `
    <app-dialog id="full">
      <button (click)="saved.set(true)">Save</button>
      <h3 dialog-title>Edit profile</h3>
      <p>Change your display name.</p>
      @if (saved()) {
        <p>Saved!</p>
      }
      <ng-container ngProjectAs="[dialog-title]"><small> (draft)</small></ng-container>
    </app-dialog>

    <app-dialog id="bare">
      <p>No title and no buttons were provided.</p>
    </app-dialog>
  `,
})
export class AppComponent {
  saved = signal(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 19 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 the APP_INITIALIZER token and how is it used to load configuration at startup?

Continue