How to Provide Multiple Default Slots for Angular ng-Content with Fallback Content
You can declare multiple default <ng-content> slots in a single Angular component, and each will render its own fallback markup when the parent provides no projected content for that slot.
When building reusable Angular components, you often need to let consumers inject custom content while still displaying sensible defaults when they omit specific sections. Understanding how to provide multiple default slots for Angular ng-content ensures your components remain flexible and self-contained without requiring complex conditional logic in the parent template.
Understanding Default Slots and Fallback Content in Angular
Angular’s content projection mechanism treats every <ng-content> element in a component’s template as a slot. A slot without a select attribute is the default slot—it receives all nodes that are not matched by any other slot.
When a slot receives no nodes from the parent, Angular renders the fallback content placed directly inside the <ng-content> tags. This fallback is static markup defined in the component’s own template, not data passed from the parent.
How Angular Processes Multiple Default Slots
During component compilation, Angular builds an ng-content selector list (ngContentSelectors) from every <ng-content> element discovered in the template. This list, along with the projectable nodes supplied by the parent, is processed by the projection instruction defined in packages/core/src/render3/instructions/projection.ts【/tmp/instagit_jlapoup4/packages/core/src/render3/instructions/projection.ts#L72-L202】.
The runtime executes the following steps:
- Matches nodes against each selector, including the empty selector (
'') that represents default slots. - Creates a
projectableNodesmatrix where each row corresponds to a specific slot index. - Renders fallback content when a row in the matrix is empty, displaying the static children written inside that
<ng-content>element. This behavior is verified in the core acceptance test suite atpackages/core/test/acceptance/content_spec.ts【/tmp/instagit_jlapoup4/packages/core/test/acceptance/content_spec.ts#L1563-L1595】.
The component creation entry point that wires the selector list to the view is ComponentRef.create in packages/core/src/render3/component_ref.ts【/tmp/instagit_jlapoup4/packages/core/src/render3/component_ref.ts#L256-L336】, while the component definition storing the selector list resides in packages/core/src/render3/component.ts【/tmp/instagit_jlapoup4/packages/core/src/render3/component.ts#L70-L101】.
Implementing Multiple Default Slots with Fallback Content
To provide multiple default slots, declare several <ng-content> elements without select attributes. Each can contain unique fallback markup that renders when the parent omits content for that specific slot.
Component Template with Three Default Slots
<!-- file: src/app/multi-slot/multi-slot.component.html -->
<div class="card">
<!-- First default slot -->
<ng-content>
<header class="default-header">
<h2>Default Header</h2>
</header>
</ng-content>
<!-- Second default slot -->
<ng-content>
<section class="default-body">
<p>No body content provided.</p>
</section>
</ng-content>
<!-- Third default slot -->
<ng-content>
<footer class="default-footer">
<small>Default Footer</small>
</footer>
</ng-content>
</div>
Usage Without Projected Content
When the consumer provides no content, all three fallbacks appear:
<!-- file: src/app/app.component.html -->
<app-multi-slot></app-multi-slot>
Result: The component renders the default header, default body paragraph, and default footer in the order defined in the template.
Usage With Partial Content
If you need to target a specific slot while keeping fallbacks for others, you must use selectors. Multiple default slots without selectors compete for the same content—Angular projects the entire fragment into the first default slot that appears in the template.
<app-multi-slot>
<!-- This content lands in the FIRST default slot only -->
<p>Custom content</p>
</app-multi-slot>
To create distinct, targetable slots while preserving a default fallback, assign selectors to specific slots and leave one unselected:
<!-- Component template -->
<ng-content select="[header]">
<h2>Default Header</h2>
</ng-content>
<ng-content>
<p>Default Body (catches everything else)</p>
</ng-content>
Summary
- Angular treats each
<ng-content>element as a slot, and slots without aselectattribute are default slots. - You can declare multiple default slots in a single component template to create distinct projection areas.
- When a slot receives no projected nodes, Angular renders the fallback content placed inside the
<ng-content>tags, as implemented inpackages/core/src/render3/instructions/projection.ts. - Without selectors, projected content flows into the first default slot; use the
selectattribute to target specific slots while keeping a catch-all default slot with its own fallback.
Frequently Asked Questions
Can I have multiple default ng-content slots without selectors?
Yes. You can place multiple <ng-content></ng-content> elements in your template, each containing its own fallback markup. When the parent provides no content, every slot renders its own default UI. However, if the parent does provide content, Angular projects it into the first default slot only, leaving the others to display their fallbacks.
How does Angular decide which slot receives projected content?
Angular builds an ngContentSelectors list during compilation and processes it in packages/core/src/render3/instructions/projection.ts. The runtime matches projected nodes against each selector in order. The first selector that matches a node captures it. For default slots (empty selector), the first default slot in template order receives all unmatched nodes.
What happens if I provide content but no slot matches the selector?
If you project content that does not match any select attribute (for example, a plain <div> when all slots require specific attributes), the content is captured by the default slot—the <ng-content> without a selector. If no default slot exists, the unmatched content is discarded and not rendered.
Is there a performance cost to declaring multiple default slots?
The performance impact is negligible. The Angular compiler generates a static ngContentSelectors array, and the runtime projection logic in packages/core/src/render3/instructions/projection.ts executes a simple matrix mapping of nodes to slots. The presence of additional fallback content increases bundle size slightly, but the runtime cost of the projection algorithm remains constant relative to the number of slots.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →