Skip to content
corpus.web

Content Projection

Content projection passes markup written between a component's tags into its template, the Angular equivalent of a web component slot

Baseline Angular 22.1.1
Kind Concept
View source

Sometimes you'll build components that share the same layout but differ in labels or inner content. You could pass everything through @Input properties — but what happens to markup placed between a component's opening and closing tags? Can we drop template content inside a component tag and have it appear where we want?

Content projection (similar to web component slot) solves this.

ng-content and common questions

How do I use ng-content?

Suppose we reuse the toggle component from component interactions for a customer survey. Questions are Yes/No, but each question has a different label. How do we make the toggle flexible without adding more inputs? Project the content passed between the component tags.

Place ng-content anywhere in the component template:

toggle.component.html

html
<div  class="toggle-wrapper"  [class.checked]="checked"  tabindex="0"  (click)="toggle()">  <div class="toggle"></div></div><div class="toogle-label">  <ng-content></ng-content></div>

app.component.html

html
<app-toggle [(checked)]="questions.question1">  <span>Question 1</span></app-toggle>
<app-toggle [(checked)]="questions.question2">  <span>Question 2</span></app-toggle>

Can I use multiple ng-content tags?

What if you put ng-content twice in the template — does content appear in both places?

toggle.component.html

html
<div class="toogle-label">  <div>content 1</div>  <ng-content></ng-content></div>
<div class="toogle-label">  <div>content 2</div>  <ng-content></ng-content></div>

Only content 2 shows with the projected label. With multiple unqualified ng-content tags, only the last one receives the content — like having a single slot. Use one ng-content without a selector, or use selectors (below).

multiple ng-content
multiple ng-content

ng-content and selectors

HTML <table> reorders <thead>, <tbody>, and <tfoot> regardless of source order. You can do something similar with ng-content selectors — and this also lets you use multiple projection slots.

Selector forms:

  • Tag selector: <ng-content select="some-component-selector-or-html-tag"></ng-content>
  • CSS class selector: <ng-content select=".some-class"></ng-content>
  • Attribute selector: <ng-content select="[some-attr]"></ng-content>
  • Combined: <ng-content select="some-tag[some-attr]"></ng-content>

Toggle component example:

toggle.component.html

html
<header>  <ng-content select=".toogle-header"></ng-content></header><div  class="toggle-wrapper"  [class.checked]="checked"  tabindex="0"  (click)="toggle()">  <div class="toggle"></div></div><div class="toogle-label">  <ng-content select="label"></ng-content></div>
<div class="toggle-content">  <ng-content></ng-content></div>

app.component.html

html
<app-toggle [(checked)]="questions.question1">  <h3 class="toogle-header">Header 1</h3>  <label>Question 1</label>  <span>Some paragraph</span></app-toggle>

Even if you reorder projected elements, the toggle component displays them in the layout defined by its ng-content slots:

html
<app-toggle [(checked)]="questions.question2">  <h3 class="toogle-header">Header 2</h3>  <span>Some paragraph 2</span>  <label>Question 2</label></app-toggle>

Note: when multiple elements match a select selector, ng-content projects all of them.

ng-content and ngProjectAs

Suppose the toggle expects content with selector app-label, but consumers want a plain HTML <label>, a different label component, or a label wrapped in a div. The select attribute won't match.

Use ngProjectAs to tell Angular how to treat projected content:

app.component.html

html
<app-toggle [(checked)]="questions.question1">  <h3 class="toogle-header">Header 1</h3>  <label ngProjectAs="app-label">Question 1</label>  <span>Some paragraph</span></app-toggle>

Many libraries use this technique for customization — for example, ngx-dropzone.

Summary

ng-content (and the slot concept in other frameworks) helps you build highly reusable components. This article introduced the basics; we'll revisit projection when we cover ContentChild in templates architecture.

Further reading:

Youtube Video

Content Projection
Content Projection

Code sample

https://stackblitz.com/edit/angular-ivy-100-days-of-code-day-13?file=src%2Fapp%2Ftoggle%2Ftoggle.component.html

0%