# Content projection

This topic describes how to use content projection to create flexible, reusable components.

<div class="alert is-helpful">

To view or download the example code used in this topic, see the <live-example></live-example>.

</div>

Content projection is a pattern in which you insert, or *project*, the content you want to use inside another component.
For example, you could have a `Card` component that accepts content provided by another component.

The following sections describe common implementations of content projection in Angular, including:

| Content projection                             | Details |
|:---                                            |:---     |
| [Single-slot content projection](#single-slot) | With this type of content projection, a component accepts content from a single source.                  |
| [Multi-slot content projection](#multi-slot)   | In this scenario, a component accepts content from multiple sources.                                     |
| [Conditional content projection](#conditional) | Components that use conditional content projection render content only when specific conditions are met. |

<a id="single-slot"></a>

## Single-slot content projection

The most basic form of content projection is *single-slot content projection*.
Single-slot content projection refers to creating a component into which you can project one component.

To create a component that uses single-slot content projection:

1.  [Create a component](guide/component-overview#creating-a-component).
1.  In the template for your component, add an `<ng-content>` element where you want the projected content to appear.

For example, the following component uses an `<ng-content>` element to display a message.

<code-example header="content-projection/src/app/zippy-basic/zippy-basic.component.ts" path="content-projection/src/app/zippy-basic/zippy-basic.component.ts"></code-example>

With the `<ng-content>` element in place, users of this component can now project their own message into the component.
For example:

<code-example header="content-projection/src/app/app.component.html" path="content-projection/src/app/app.component.html" region="single-slot"></code-example>

<div class="alert is-helpful">

The `<ng-content>` element is a placeholder that does not create a real DOM element.
Custom attributes applied to `<ng-content>` are ignored.

</div>

<a id="multi-slot"></a>

## Multi-slot content projection

A component can have multiple slots.
Each slot can specify a CSS selector that determines which content goes into that slot.
This pattern is referred to as *multi-slot content projection*.
With this pattern, you must specify where you want the projected content to appear.
You accomplish this task by using the `select` attribute of `<ng-content>`.

To create a component that uses multi-slot content projection:

1.  [Create a component](guide/component-overview#creating-a-component).
1.  In the template for your component, add an `<ng-content>` element where you want the projected content to appear.
1.  Add a `select` attribute to the `<ng-content>` elements.
    Angular supports [selectors](https://developer.mozilla.org/docs/Web/CSS/CSS_Selectors) for any combination of tag name, attribute, CSS class, and the `:not` pseudo-class.

    For example, the following component uses two  `<ng-content>` elements.

    <code-example header="content-projection/src/app/zippy-multislot/zippy-multislot.component.ts" path="content-projection/src/app/zippy-multislot/zippy-multislot.component.ts"></code-example>

Content that uses the `question` attribute is projected into the `<ng-content>` element with the `select=[question]` attribute.

<code-example header="content-projection/src/app/app.component.html" path="content-projection/src/app/app.component.html" region="multi-slot"></code-example>

<div class="callout is-helpful">

<header>ng-content without a select attribute</header>

If your component includes an `<ng-content>` element without a `select` attribute, that instance receives all projected components that do not match any of the other `<ng-content>` elements.

In the preceding example, only the second `<ng-content>` element defines a `select` attribute.
As a result, the first `<ng-content>` element receives any other content projected into the component.

</div>

<a id="conditional"></a>

## Conditional content projection

If your component needs to *conditionally* render content, or render content multiple times, you should configure that component to accept an `<ng-template>` element that contains the content you want to conditionally render.

Using an `<ng-content>` element in these cases is not recommended, because when the consumer of a component supplies the content, that content is *always* initialized, even if the component does not define an `<ng-content>` element or if that `<ng-content>` element is inside of an `ngIf` statement.

With an `<ng-template>` element, you can have your component explicitly render content based on any condition you want, as many times as you want.
Angular will not initialize the content of an `<ng-template>` element until that element is explicitly rendered.

The following steps demonstrate a typical implementation of conditional content projection using `<ng-template>`.

1.  [Create a component](guide/component-overview#creating-a-component).
1.  In the component that accepts an `<ng-template>` element, use an `<ng-container>` element to render that template, such as:

    <code-example header="content-projection/src/app/example-zippy.template.html" path="content-projection/src/app/example-zippy.template.html" region="ng-container"></code-example>

    This example uses the `ngTemplateOutlet` directive to render a given `<ng-template>` element, which you will define in a later step.
    You can apply an `ngTemplateOutlet` directive to any type of element.
    This example assigns the directive to an `<ng-container>` element because the component does not need to render a real DOM element.

1.  Wrap the `<ng-container>` element in another element, such as a `div` element, and apply your conditional logic.

    <code-example header="content-projection/src/app/example-zippy.template.html" path="content-projection/src/app/example-zippy.template.html" region="ngif"></code-example>

1.  In the template where you want to project content, wrap the projected content in an `<ng-template>` element, such as:

    <code-example header="content-projection/src/app/app.component.html"  region="ng-template" path="content-projection/src/app/app.component.html"></code-example>

    The `<ng-template>` element defines a block of content that a component can render based on its own logic.
    A component can get a reference to this template content, or `TemplateRef`, by using either the `@ContentChild` or `@ContentChildren` decorators.
    The preceding example creates a custom directive, `appExampleZippyContent`, as an API to mark the `<ng-template>` for the component's content.
    With the `TemplateRef`, the component can render the referenced content by using either the `ngTemplateOutlet` directive, or with the `ViewContainerRef` method `createEmbeddedView()`.

1.  [Create an attribute directive](guide/attribute-directives#building-an-attribute-directive) with a selector that matches the custom attribute for your template.
    In this directive, inject a `TemplateRef` instance.

    <code-example header="content-projection/src/app/example-zippy.component.ts" path="content-projection/src/app/example-zippy.component.ts" region="zippycontentdirective"></code-example>

    In the previous step, you added an `<ng-template>` element with a custom attribute, `appExampleZippyContent`.
    This code provides the logic that Angular will use when it encounters that custom attribute.
    In this case, that logic instructs Angular to instantiate a template reference.

1.  In the component you want to project content into, use `@ContentChild` to get the template of the projected content.

    <code-example header="content-projection/src/app/example-zippy.component.ts" path="content-projection/src/app/example-zippy.component.ts" region="contentchild"></code-example>

    Prior to this step, your application has a component that instantiates a template when certain conditions are met.
    You've also created a directive that provides a reference to that template.
    In this last step, the `@ContentChild` decorator instructs Angular to instantiate the template in the designated component.

    <div class="alert is-helpful">

    In the case of multi-slot content projection, use `@ContentChildren` to get a `QueryList` of projected elements.

    </div>

<a id="ngprojectas "></a>

## Projecting content in more complex environments

As described in [Multi-slot Content Projection](#multi-slot), you typically use either an attribute, element, CSS Class, or some combination of all three to identify where to project your content.
For example, in the following HTML template, a paragraph tag uses a custom attribute, `question`, to project content into the `app-zippy-multislot` component.

<code-example header="content-projection/src/app/app.component.html" path="content-projection/src/app/app.component.html" region="multi-slot"></code-example>

In some cases, you might want to project content as a different element.
For example, the content you want to project might be a child of another element.
Accomplish this with the `ngProjectAs` attribute.

For instance, consider the following HTML snippet:

<code-example header="content-projection/src/app/app.component.html" path="content-projection/src/app/app.component.html" region="ngprojectas"></code-example>

This example uses an `<ng-container>` attribute to simulate projecting a component into a more complex structure.

<div class="callout is-helpful">

<header>Reminder</header>

The `ng-container` element is a logical construct that is used to group other DOM elements; however, the `ng-container` itself is not rendered in the DOM tree.

</div>

In this example, the content we want to project resides inside another element.
To project this content as intended, the template uses the `ngProjectAs` attribute.
With `ngProjectAs`, the entire `<ng-container>` element is projected into a component using the `[question]` selector.

<!-- links -->

<!-- external links -->

<!-- end links -->

@reviewed 2022-02-28
