Content projection is a powerful feature in Angular that allows you to create reusable and flexible components. One such element is the <ng-content> tag, which acts as a placeholder for content to be projected into your components. This guide will walk you through the essentials of using <ng-content> in Angular, providing practical examples and insights to enhance your understanding.

Introduction to ng-content

When developing Angular applications, you often need components that can contain various types of content. For instance, consider creating a custom card component:

@Component({
  selector: 'custom-card',
  template: '<div class="card-shadow"> <!-- card content goes here --> </div>',
})
export class CustomCard { /* ... */ }

To make this component more flexible, you can use the <ng-content> element. This element serves as a placeholder for the content that will be projected into the component:

@Component({
  selector: 'custom-card',
  template: '<div class="card-shadow"> <ng-content></ng-content> </div>',
})
export class CustomCard { /* ... */ }

The <ng-content> element is similar to the native <slot> element but includes Angular-specific functionalities.

How ng-content Works

When you use a component containing <ng-content>, any children of the component's host element are rendered, or projected, at the location of the <ng-content>:

@Component({
  selector: 'custom-card',
  template: `
    <div class="card-shadow">
      <ng-content></ng-content>
    </div>
  `,
})
export class CustomCard { /* ... */ }

Using the Component

<custom-card>
  <p>This is the projected content</p>
</custom-card>

Rendered DOM

<custom-card>
  <div class="card-shadow">
    <p>This is the projected content</p>
  </div>
</custom-card>

In Angular, the children passed to the component are referred to as the component's content, distinct from the component's view, which is defined in the component's template.

Multiple Content Placeholders

Angular allows projecting multiple elements into different <ng-content> placeholders based on CSS selectors. For example, you can create placeholders for a card title and card body:

Component Template

<div class="card-shadow">
  <ng-content select="card-title"></ng-content>
  <div class="card-divider"></div>
  <ng-content select="card-body"></ng-content>
</div>

Using the Component

<custom-card>
  <card-title>Hello</card-title>
  <card-body>Welcome to the example</card-body>
</custom-card>

Rendered DOM

<custom-card>
  <div class="card-shadow">
    <card-title>Hello</card-title>
    <div class="card-divider"></div>
    <card-body>Welcome to the example</card-body>
  </div>
</custom-card>

The <ng-content> placeholder supports the same CSS selectors as component selectors. If a placeholder without a select attribute is included, it captures all elements that do not match any other select attributes:

Aliasing Content for Projection

Angular supports a special attribute, ngProjectAs, allowing you to specify a CSS selector on any element. This attribute ensures that Angular compares the element against the specified selector instead of the element's identity:

Component Template

<div class="card-shadow">
  <ng-content select="card-title"></ng-content>
  <div class="card-divider"></div>
  <ng-content></ng-content>
</div>

Using the Component

<custom-card>
  <h3 ngProjectAs="card-title">Hello</h3>
  <p>Welcome to the example</p>
</custom-card>

Rendered DOM

<custom-card>
  <div class="card-shadow">
    <h3>Hello</h3>
    <div class="card-divider"></div>
    <p>Welcome to the example></p>
  </div>
</custom-card>

The ngProjectAs attribute supports only static values and cannot be bound to dynamic expressions.

Advanced Use Cases for ng-content

Dynamic Content with Angular CDK

The Angular Component Dev Kit (CDK) provides advanced tools for managing content projection dynamically. This can be particularly useful for complex scenarios where content needs to be manipulated or changed at runtime. While <ng-content> itself cannot be conditionally rendered or modified, Angular CDK components like portals and overlays offer alternatives for more dynamic content handling.

Implementing Multi-Content Projections

Consider an advanced component such as a custom tab layout that uses multiple content projections to display different tab contents. Each tab content can be projected into the appropriate tab panel based on the selected tab.

@Component({
  selector: 'custom-tabs',
  template: `
    <div class="tabs">
      <ng-content select="[tab-title]"></ng-content>
    </div>
    <div class="tab-content">
      <ng-content select="[tab-content]"></ng-content>
    </div>
  `,
})
export class CustomTabs { /* ... */ }

Using the Custom Tabs Component

<custom-tabs>
  <div tab-title>Tab 1</div>
  <div tab-title>Tab 2</div>
  <div tab-content>Content for Tab 1</div>
  <div tab-content>Content for Tab 2</div>
</custom-tabs>

Rendered DOM

<custom-tabs>
  <div class="tabs">
    <div>Tab 1</div>
    <div>Tab 2</div>
  </div>
  <div class="tab-content">
    <div>Content for Tab 1</div>
    <div>Content for Tab 2</div>
  </div>
</custom-tabs>

This example demonstrates how multiple <ng-content> elements can be used to create complex UI components that maintain flexibility and reusability.

Pros and Cons of Using ng-content

Pros

  • Flexibility: Allows creating highly reusable components.
  • Simplicity: Easy to implement and understand.
  • Customization: Enables component customization by projecting different content.
  • Separation of Concerns: Encourages clean separation between a component's logic and its projected content.

Cons

  • Limitations: Cannot add directives, styles, or attributes to <ng-content>.
  • Static Nature: Cannot conditionally include <ng-content> with Angular structural directives.
  • Performance: Overuse of content projection can lead to performance issues if not managed properly.
  • Debugging: Can make debugging more challenging as projected content is not part of the component's template.

Frequently Asked Questions

1. What is <ng-content> in Angular?

<ng-content> is a placeholder element in Angular that allows you to project content into a component's template.

2. Can you conditionally render <ng-content>?

No, you cannot conditionally render <ng-content> using structural directives like ngIf, ngFor, or ngSwitch.

3. How do you project multiple content sections?

You can project multiple content sections using the select attribute with CSS selectors.

4. What is ngProjectAs used for?

ngProjectAs is used to alias content for projection, allowing you to specify a CSS selector for content projection.

5. Can ngProjectAs be dynamic?

No, ngProjectAs supports only static values and cannot be bound to dynamic expressions.

6. Does <ng-content> support directives?

No, you cannot add directives to the <ng-content> element.

7. How does Angular process <ng-content>?

Angular's compiler processes <ng-content> elements at build-time to determine where to project the content.

8. Can you style <ng-content> directly?

No, you cannot directly style <ng-content>.

9. What happens if a component has no <ng-content> placeholders?

If a component has no <ng-content> placeholders, any projected content will not be rendered in the DOM.

10. How is <ng-content> different from the native <slot> element?

While <ng-content> and <slot> serve similar purposes, <ng-content> includes additional Angular-specific functionalities.

Conclusion

Using <ng-content> for content projection in Angular provides a powerful way to create reusable and flexible components. Whether you are developing a simple custom card or a complex UI component, understanding and leveraging content projection can significantly enhance your Angular applications.

Further Reading

Recent Articles