Table of contents
1.
Introduction
2.
Prerequisites
3.
What is Content Projection?
4.
Why Use Content Projection?
5.
Features of Content Projection
6.
How to identify if components have content projection?
7.
Content Projection Methods
7.1.
1. Single-Slot Content Projection
7.2.
2. Multi-Slot Content Projection
7.3.
3. Conditional Content Projection
7.4.
4. Projecting Components or Directives
8.
Common Implementations of Content Projection in Angular
8.1.
1. Reusable Modal Component
8.2.
2. Tab Component
9.
Projecting Content in More Complex Environments
10.
Frequently Asked Questions
10.1.
What is content projection in Angular?
10.2.
Is content projection similar to transclusion in AngularJS? 
10.3.
How does multi-slot content projection work?
11.
Conclusion
Last Updated: Feb 18, 2025
Medium

Content Projection in Angular

Author Rahul Singh
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Content projection in Angular is a technique that allows developers to pass custom content into a component's template using the <ng-content> directive. It enables better reusability and flexibility by allowing a parent component to project different content into a child component. This is commonly used in building UI libraries and dynamic components.

Content Projection in Angular

In this article, you will learn about content projection in Angular, its syntax, and how to use it effectively in applications.

Prerequisites

Before you begin learning about content projection, you should have:
 

  • Basic knowledge of Angular and TypeScript.
     
  • Familiarity with Angular components and templates.
     
  • Installed Node.js and Angular CLI to run and test examples.

What is Content Projection?

Content projection is a feature in Angularr that allows developers to insert custom content into a component. It helps create reusable UI components by enabling dynamic content injection.

For example, consider a card component where the title and content need to be dynamic. Instead of hardcoding them, we can use content projection to pass any content from the parent component.

Why Use Content Projection?

  • Reusability: Helps in building generic and reusable UI components.
     
  • Separation of concerns: Keeps the component structure clean and maintainable.
     
  • Flexibility: Allows different components to display different content dynamically.
     
  • Improves Readability: Keeps templates simple and avoids excessive logic inside components.

Features of Content Projection

  • Allows insertion of custom content inside components.
     
  • Supports single and multiple content slots.
     
  • Uses the <ng-content> directive.
     
  • Works seamlessly with Angular directives and binding.

How to identify if components have content projection?

Content projection in Angular is all about passing content from a parent component to a child component. To identify if a component uses content projection, you need to look for specific Angular features in the component’s code. Let’s discuss how you can do it:

 

1. Look for `<ng-content>` in the Child Component

The `<ng-content>` tag is the key indicator of content projection. It acts as a placeholder where the parent component’s content will be injected. If you see this tag in a component’s template, it means the component is designed to accept projected content.
 

Example:

Let’s say we have a `CardComponent` that uses content projection. Let’s see how its template might look:

<!-- card.component.html -->
<div class="card">
  <div class="card-header">
    <ng-content select="[card-header]"></ng-content>
  </div>
  <div class="card-body">
    <ng-content></ng-content>
  </div>
  <div class="card-footer">
    <ng-content select="[card-footer]"></ng-content>
  </div>
</div>

 

In this example:

  • The `<ng-content>` tag without any `select` attribute acts as a default slot for content.
     
  • The `<ng-content select="[card-header]">` and `<ng-content select="[card-footer]">` tags are used to project specific parts of the content.

 

2. Check the Parent Component’s Usage

The parent component will pass content to the child component using its selector. For example, if the child component’s selector is `app-card`, the parent component will use it like this:

 

<!-- app.component.html -->
<app-card>
  <div card-header>This is the header</div>
  <p>This is the main content.</p>
  <div card-footer>This is the footer</div>
</app-card>

 

Here:

  • The `<div card-header>` and `<div card-footer>` elements are projected into the respective slots in the `CardComponent`.
     
  • The `<p>` element is projected into the default `<ng-content>` slot.

 

3. Look for `@ContentChild` or `@ContentChildren` in the Child Component

Sometimes, content projection is used to pass not just HTML but also Angularcomponents or directives. In such cases, the child component might use `@ContentChild` or `@ContentChildren` decorators to access the projected content programmatically.

Example:

// card.component.ts
import { Component, ContentChild } from '@angular/core';
import { CardHeaderDirective } from './card-header.directive';

@Component({
  selector: 'app-card',
  templateUrl: './card.component.html',
})
export class CardComponent {
  @ContentChild(CardHeaderDirective) header: CardHeaderDirective;

  ngAfterContentInit() {
    if (this.header) {
      console.log('Header content is projected:', this.header);
    }
  }
}

 

In this example:

  • The `@ContentChild` decorator is used to query the projected content that matches the `CardHeaderDirective`.
     
  • The `ngAfterContentInit` lifecycle hook ensures the projected content is available after the component initializes.

 

4. Check for Multi-Slot Projection

If a component supports multiple slots for content projection, it will have multiple `<ng-content>` tags with `select` attributes. Each `select` attribute specifies a CSS selector to match specific elements in the parent component.

Example:

<!-- card.component.html -->
<div class="card">
  <ng-content select="[card-header]"></ng-content>
  <ng-content select="[card-body]"></ng-content>
  <ng-content select="[card-footer]"></ng-content>
</div>


In this case:

The parent component can pass different parts of the content to different slots using the corresponding attributes (`card-header`, `card-body`, `card-footer`).


Summary of Identification

To identify if a component uses content projection:

1. Look for `<ng-content>` tags in the component’s template.
 

2. Check how the parent component uses the child component’s selector.
 

3. Look for `@ContentChild` or `@ContentChildren` decorators in the child component’s TypeScript file.
 

4. Check if the component supports multi-slot projection using `select` attributes.

Content Projection Methods

Content projection in Angular can be implemented in several ways, depending on the complexity and flexibility you need. Let’s discuss the most common methods:

1. Single-Slot Content Projection

This is the simplest form of content projection, where a component accepts content in a single slot. The parent component passes content, and the child component projects it using the `<ng-content>` tag.

 

Example:

Let’s create a `MessageComponent` that accepts a single block of content.

 

Step 1: Create the Child Component

// message.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-message',
  template: `
    <div class="message">
      <ng-content></ng-content>
    </div>
  `,
  styles: [
    `
      .message {
        border: 1px solid ccc;
        padding: 10px;
        margin: 10px;
        background-color: f9f9f9;
      }
    `,
  ],
})
export class MessageComponent {}

 

Step 2: Use the Child Component in the Parent Component

<!-- app.component.html -->
<app-message>
  <p>This is a simple message displayed using content projection.</p>
</app-message>

 

Explanation:

  • The `<ng-content>` tag in `MessageComponent` acts as a placeholder for the content passed by the parent component.
     
  • The parent component (`AppComponent`) passes a `<p>` element, which is projected into the `MessageComponent`.

2. Multi-Slot Content Projection

In multi-slot projection, a component can accept content in multiple slots. Each slot is identified using the `select` attribute of the `<ng-content>` tag.
 

Example:

Let’s create a `CardComponent` that accepts content in three slots: header, body, and footer.

 

Step 1: Create the Child Component

// card.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-card',
  template: `
    <div class="card">
      <div class="card-header">
        <ng-content select="[card-header]"></ng-content>
      </div>
      <div class="card-body">
        <ng-content select="[card-body]"></ng-content>
      </div>
      <div class="card-footer">
        <ng-content select="[card-footer]"></ng-content>
      </div>
    </div>
  `,
  styles: [
    `
      .card {
        border: 1px solid ccc;
        padding: 10px;
        margin: 10px;
        background-color: f9f9f9;
      }
      .card-header,
      .card-footer {
        font-weight: bold;
      }
    `,
  ],
})
export class CardComponent {}

 

Step 2: Use the Child Component in the Parent Component

<!-- app.component.html -->
<app-card>
  <div card-header>This is the header</div>
  <p card-body>This is the main content of the card.</p>
  <div card-footer>This is the footer</div>
</app-card>

 

Explanation:

  • The `select` attribute in `<ng-content>` specifies which content to project into each slot.
     
  • The parent component uses attributes (`card-header`, `card-body`, `card-footer`) to pass content to the respective slots.

3. Conditional Content Projection

Sometimes, you may want to conditionally project content based on certain criteria. This can be achieved using Angular’s structural directives like `ngIf`.

 

Example:

Let’s modify the `CardComponent` to conditionally display the footer.

 

Step 1: Update the Child Component

// card.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-card',
  template: `
    <div class="card">
      <div class="card-header">
        <ng-content select="[card-header]"></ng-content>
      </div>
      <div class="card-body">
        <ng-content select="[card-body]"></ng-content>
      </div>
      <div class="card-footer" ngIf="showFooter">
        <ng-content select="[card-footer]"></ng-content>
      </div>
    </div>
  `,
  styles: [
    `
      .card {
        border: 1px solid ccc;
        padding: 10px;
        margin: 10px;
        background-color: f9f9f9;
      }
      .card-header,
      .card-footer {
        font-weight: bold;
      }
    `,
  ],
})
export class CardComponent {
  @Input() showFooter: boolean = true;
}

 

Step 2: Use the Child Component in the Parent Component

<!-- app.component.html -->
<app-card [showFooter]="false">
  <div card-header>This is the header</div>
  <p card-body>This is the main content of the card.</p>
  <div card-footer>This is the footer (will not be displayed)</div>
</app-card>

 

Explanation:

  • The `showFooter` input property controls whether the footer content is projected.
     
  • The parent component sets `[showFooter]="false"`, so the footer content is not displayed.

4. Projecting Components or Directives

Content projection can also be used to pass entire components or directives into a child component. This is useful for creating highly reusable and customizable components.

 

Example:

Let’s create a `TabComponent` that accepts other components as projected content.

 

Step 1: Create the Child Component

// tab.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-tab',
  template: `
    <div class="tab">
      <ng-content></ng-content>
    </div>
  `,
  styles: [
    `
      .tab {
        border: 1px solid ccc;
        padding: 10px;
        margin: 10px;
        background-color: f9f9f9;
      }
    `,
  ],
})
export class TabComponent {}

 

Step 2: Use the Child Component in the Parent Component

<!-- app.component.html -->
<app-tab>
  <app-message>
    <p>This is a message inside a tab.</p>
  </app-message>
</app-tab>

 

Explanation:

  • The `TabComponent` projects the `MessageComponent` into its template.
     
  • This allows for nesting components and creating complex layouts.

 

Summary of Content Projection Methods

1. Single-slot projection: Use `<ng-content>` without a `select` attribute.
 

2. Multi-slot projection: Use `<ng-content>` with the `select` attribute to define multiple slots.
 

3. Conditional projection: Use structural directives like `ngIf` to conditionally project content.

 

4. Projecting components or directives: Pass entire components or directives as projected content.

Common Implementations of Content Projection in Angular

1. Reusable Modal Component

Content projection is widely used in modal dialogs to display different content dynamically.

modal.component.html

<div class="modal">
  <div class="modal-header">
    <ng-content select=".header"></ng-content>
  </div>
  <div class="modal-body">
    <ng-content></ng-content>
  </div>
</div>


app.component.html

<app-modal>
  <h2 class="header">Modal Title</h2>
  <p>This is the modal content.</p>
</app-modal>


Output:

Modal Title
This is the modal content.

2. Tab Component

A tab component allows projecting different tab contents dynamically.

tab.component.html

<div class="tab">
  <ng-content select=".tab-title"></ng-content>
  <ng-content select=".tab-content"></ng-content>
</div>


app.component.html

<app-tab>
  <span class="tab-title">Tab 1</span>
  <p class="tab-content">This is content for Tab 1</p>
</app-tab>

 

Output:

Tab 1
This is content for Tab 1

Projecting Content in More Complex Environments

Content projection can be used in complex scenarios, such as dynamic forms, nested components, and component composition.

For example, we can use content projection inside dynamic form components to insert different types of form elements dynamically.

<app-form>
  <input type="text" placeholder="Enter your name" />
  <button>Submit</button>
</app-form>

 

This method helps create highly reusable and maintainable components.

Frequently Asked Questions

What is content projection in Angular?

Content projection allows a component to accept dynamic content using the <ng-content> directive. It helps in creating reusable components like cards, modals, and tabs.

Is content projection similar to transclusion in AngularJS? 

Yes, content projection in Angular serves a similar purpose as transclusion in AngularJS. However, in Angular, content projection is implemented using <ng-content>, which is more powerful and flexible compared to the older transclusion approach.

How does multi-slot content projection work?

Multi-slot projection allows multiple content areas within a component by using the select attribute inside <ng-content>.

Conclusion

In this article, we discussed Content Projection in Angular a technique that allows developers to pass content from a parent component into a child component using the <ng-content> directive. It helps in creating reusable and flexible components. Understanding Content Projection improves component design, enhances reusability, and simplifies UI development in Angular applications.

Live masterclass