Angular: Advanced Multi-Slot Content Projection with ng-content in a Reusable Modal

Abhishek Wadalkar
4 min readJan 1, 2025

--

When working with Angular, one of the most powerful features at your disposal is Content Projection — a technique that allows you to insert dynamic content into components. A particularly useful application of this is creating reusable UI components like modals, where you can inject custom content depending on the context in which the modal is used.

In this post, we’ll dive into how to implement multi-slot content projection using Angular ng-content. By the end of the post, you'll know how to build a reusable modal that accepts different content in various "slots."

Understanding Content Projection

Content projection in Angular allows you to define placeholders in a component and inject external content into those placeholders. It’s achieved using the <ng-content> directive.

Basic Content Projection

Before we jump into advanced techniques, let’s first quickly review how simple content projection works. Imagine we have a modal component:

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

In this example, we’re creating a modal component with 3 parts: header, body, and footer. We use <ng-content> to project content into the appropriate sections.

Building the Reusable Modal with Multi-Slot Content Projection

Now, let’s build a reusable modal that can accept different content in its header, body, and footer. Instead of having a single <ng-content>, we’ll use multiple ng-content slots for more control over where the content gets inserted.

1: Create the Modal Component

Let’s start by creating a modal component that can accept dynamic content in its header, body, and footer.

<!-- modal.component.html -->
<div class="modal" *ngIf="isVisible">
<div class="modal-dialog">
<div class="modal-header">
<ng-content select="[modal-header]"></ng-content>
</div>

<div class="modal-body">
<ng-content select="[modal-body]"></ng-content>
</div>

<div class="modal-footer">
<ng-content select="[modal-footer]"></ng-content>
</div>
</div>
</div>
// modal.component.ts
import { Component, Input } from '@angular/core';

@Component({
selector: 'app-modal',
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.css']
})
export class ModalComponent {
@Input() isVisible: boolean = false;
}

2: Using the Modal Component

In your parent component, you can now inject content into the modal through the designated slots.

<!-- app.component.html -->
<app-modal [isVisible]="isModalVisible">
<div modal-header>
<h2>Custom Modal Header</h2>
</div>
<div modal-body>
<p>This is the body content of the modal.</p>
<p>You can put anything here!</p>
</div>
<div modal-footer>
<button (click)="closeModal()">Close</button>
</div>
</app-modal>

<button (click)="openModal()">Open Modal</button>
// app.component.ts
import { Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
isModalVisible: boolean = false;

openModal() {
this.isModalVisible = true;
}

closeModal() {
this.isModalVisible = false;
}
}

3: Styling the Modal (Optional)

You can style the modal to make it look more like a traditional modal.

/* modal.component.css */
.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
}

.modal-dialog {
background: white;
padding: 20px;
border-radius: 8px;
width: 50%;
}

.modal-header {
font-size: 1.5em;
font-weight: bold;
}

.modal-body {
padding: 20px 0;
}

.modal-footer {
display: flex;
justify-content: flex-end;
padding-top: 10px;
}

4: Testing the Modal

When you run the app, you’ll see a button labeled “Open Modal.” When clicked, the modal appears with custom header, body, and footer content.

  • The header contains a <h2>Custom Modal Header</h2>.
  • The body has two <p> tags.
  • The footer has a “Close” button.

This modal component is reusable and flexible. You can now project different content into the modal each time you use it.

Advanced Tips

1. Default Content with <ng-content>

If you want to provide default content when no content is projected, you can place default content inside the <ng-content> tags. For example:

<!-- modal.component.html -->
<div class="modal-body">
<ng-content select="[modal-body]">
<p>This is the default body content if none is provided.</p>
</ng-content>
</div>

2. Multiple Slots without select

If you don’t want to use the select attribute, you can have a more generic content projection with multiple slots. For example:

<!-- modal.component.html -->
<div class="modal-header">
<ng-content></ng-content>
</div>
<div class="modal-body">
<ng-content></ng-content>
</div>

However, you may lose the flexibility of controlling which part of the modal gets which content.

Conclusion

By applying multi-slot content projection, you can control exactly where each piece of content appears in your modal, making it adaptable to various use cases. Whether you’re building complex modals, dynamic forms, or any component that requires dynamic content, mastering this technique will help you create clean, maintainable, and highly reusable components in Angular.

--

--

Abhishek Wadalkar
Abhishek Wadalkar

Written by Abhishek Wadalkar

Passionate Frontend developer with 4 years experience, crafting seamless, user-centric web experiences. Exploring the world of web development and constantly.

No responses yet