An element or <ng-template> inside a control flow block would be projected into a specific <ng-content> slot, but isn't because the block has more than one root node.
import {Component} from '@angular/core';
@Component({
selector: 'app-card',
template: `
<ng-content select="[card-title]" />
<ng-content />
`,
})
class Card {}
@Component({
imports: [Card],
// NG8011: <h2 card-title> is not projected into the "[card-title]" slot because the @if
// block has two root nodes (the h2 and the p).
template: `
<app-card>
@if (showTitle) {
<h2 card-title>Title</h2>
<p>Subtitle</p>
}
</app-card>
`,
})
class MyComponent {
showTitle = true;
}
Debugging the error
Control flow blocks emulate the content projection behavior of *ngIf and *ngFor, which project the element they are applied to.
This only works if the block has a single root node.
When the block has more than one root node, Angular can't use the element to choose a slot, so <h2 card-title> ends up in the default <ng-content /> slot of Card instead of the [card-title] slot.
Text counts as a root node, so a stray line of text next to the projected element causes the same problem, unless the component that contains the block sets preserveWhitespaces: true, in which case whitespace counts as well.
To resolve the error, pick one of the following approaches:
Wrap the content in an
<ng-container>that usesngProjectAsto match the selector of the slot. Everything inside the container is projected into that slot.Split the content across multiple blocks, so that each one has a single projectable node at its root.