What Is Content Projection in Angular?
What is Content Projection?
Content projection is an Angular feature that allows a parent component to provide HTML/content to a child component, and the child decides where that content should appear.
Angular uses:
<ng-content></ng-content>
as the placeholder for the projected content.
In simple terms:
Parent provides the content → Child provides the layout/container.
Parent
│
│ HTML / Content
▼
Child Component
│
│ <ng-content>
▼
Rendered UI
A common example is a reusable Card component.
Why Do We Need Content Projection?
Suppose you want one reusable card component, but each card should contain different content:
Card
├── Product information
├── Customer information
├── Employee information
└── Order information
You could create many inputs:
title = input<string>();
description = input<string>();
buttonText = input<string>();
But if the parent needs to provide flexible HTML such as headings, paragraphs, buttons, images, or even other components, creating an input for everything becomes cumbersome.
Content projection allows this:
<app-card>
<h2>Laptop</h2>
<p>Price: ₹50,000</p>
<button>Buy Now</button>
</app-card>
The Card component doesn't need to know what content will be provided.
Purpose
Content projection is mainly used to create flexible and reusable UI/container components.
Common examples:
- Cards
- Dialogs
- Modals
- Panels
- Tabs
- Layout components
- Form containers
- Headers and footers
- Reusable UI libraries
Full Code Example
Let's create a reusable Card component.
Project Structure
src/app/
│
├── app.ts
├── app.html
│
└── card/
├── card.ts
├── card.html
└── card.css
card.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-card',
templateUrl: './card.html',
styleUrl: './card.css'
})
export class Card {
}
card.html
<div class="card">
<ng-content></ng-content>
</div>
card.css
.card {
border: 1px solid #ccc;
padding: 20px;
margin: 20px;
border-radius: 8px;
}
app.ts
import { Component } from '@angular/core';
import { Card } from './card/card';
@Component({
selector: 'app-root',
imports: [Card],
templateUrl: './app.html'
})
export class App {
}
app.html
<h1>Products</h1>
<app-card>
<h2>Laptop</h2>
<p>Price: ₹50,000</p>
<p>High-performance business laptop.</p>
<button>Buy Now</button>
</app-card>
Code Explanation
Step 1 – Parent Provides Content
In app.html:
<app-card>
<h2>Laptop</h2>
<p>Price: ₹50,000</p>
<p>High-performance business laptop.</p>
<button>Buy Now</button>
</app-card>
Everything between:
<app-card>
and:
</app-card>
is the content provided by the parent.
Step 2 – Child Defines the Projection Location
Inside card.html:
<div class="card">
<ng-content></ng-content>
</div>
<ng-content> tells Angular:
Insert the content supplied by the parent here.
Step 3 – Angular Projects the Content
Angular effectively produces:
<div class="card">
<h2>Laptop</h2>
<p>Price: ₹50,000</p>
<p>High-performance business laptop.</p>
<button>Buy Now</button>
</div>
The flow is:
Parent
<app-card>
<h2>Laptop</h2>
<p>₹50,000</p>
<button>Buy Now</button>
</app-card>
│
│ Content Projection
▼
Child
<div class="card">
<ng-content></ng-content>
</div>
│
▼
Rendered UI
┌─────────────────────────┐
│ Laptop │
│ ₹50,000 │
│ High-performance laptop │
│ │
│ [ Buy Now ] │
└─────────────────────────┘
Types of Content Projection
Angular mainly supports:
- Single-slot content projection
- Multi-slot content projection
1. Single-Slot Content Projection
Single-slot projection means the child has one location for projected content.
<ng-content></ng-content>
The example above is single-slot projection.
Parent:
<app-card>
<h2>Laptop</h2>
<p>₹50,000</p>
<button>Buy</button>
</app-card>
Child:
<div class="card">
<ng-content></ng-content>
</div>
Everything is projected into the same location.
2. Multi-Slot Content Projection
Sometimes we want different parent content to appear in different locations.
For example:
Card
│
├── Header
├── Body
└── Footer
We can use multiple <ng-content> elements with select.
Full Multi-Slot Example
card.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-card',
templateUrl: './card.html',
styleUrl: './card.css'
})
export class Card {
}
card.html
<div class="card">
<header class="card-header">
<ng-content select="[card-header]"></ng-content>
</header>
<main class="card-body">
<ng-content select="[card-body]"></ng-content>
</main>
<footer class="card-footer">
<ng-content select="[card-footer]"></ng-content>
</footer>
</div>
card.css
.card {
border: 1px solid #ccc;
padding: 20px;
border-radius: 8px;
}
.card-header {
font-weight: bold;
margin-bottom: 10px;
}
.card-body {
margin-bottom: 10px;
}
.card-footer {
margin-top: 10px;
}
app.ts
import { Component } from '@angular/core';
import { Card } from './card/card';
@Component({
selector: 'app-root',
imports: [Card],
templateUrl: './app.html'
})
export class App {
}
app.html
<app-card>
<h2 card-header>
Laptop
</h2>
<div card-body>
<p>Price: ₹50,000</p>
<p>High-performance business laptop.</p>
</div>
<div card-footer>
<button>Buy Now</button>
</div>
</app-card>
Multi-Slot Code Explanation
The child contains:
<ng-content select="[card-header]"></ng-content>
Angular looks for content matching:
[card-header]
The parent provides:
<h2 card-header>
Laptop
</h2>
Therefore Angular places it in the header.
Similarly:
<ng-content select="[card-body]"></ng-content>
matches:
<div card-body>
And:
<ng-content select="[card-footer]"></ng-content>
matches:
<div card-footer>
The flow is:
Parent Content Child Slot
<h2 card-header> ────────► [card-header]
<div card-body> ────────► [card-body]
<div card-footer> ────────► [card-footer]
Result:
┌────────────────────────────┐
│ Laptop │ ← Header
├────────────────────────────┤
│ Price: ₹50,000 │
│ High-performance laptop │ ← Body
├────────────────────────────┤
│ [ Buy Now ] │ ← Footer
└────────────────────────────┘
What Does select Do?
The select property determines which parent content should be inserted into a particular <ng-content> slot.
For example:
<ng-content select="[card-header]"></ng-content>
matches:
<h2 card-header>
Laptop
</h2>
This allows us to create multiple projection locations.
Content Projection vs input()
This is an important distinction.
input()
Use input() when the parent needs to pass data.
Child:
productName = input<string>();
Parent:
<app-product
[productName]="name">
</app-product>
The child decides how to display the data.
Content Projection
Use content projection when the parent needs to provide UI content/markup.
<app-card>
<h2>Laptop</h2>
<p>₹50,000</p>
<button>Buy</button>
</app-card>
The child decides where the supplied content should appear.
Difference
input() |
Content Projection |
|---|---|
| Passes data | Projects content |
| Parent → Child | Parent content → Child template |
| String, number, object, etc. | HTML/elements/components |
| Child controls rendering | Parent controls projected markup |
input() |
<ng-content> |
Easy way to remember:
input()
│
└── Pass DATA
ng-content
│
└── Pass CONTENT / UI
Can We Project Angular Components?
Yes.
Projected content doesn't have to be plain HTML.
For example:
<app-card>
<app-product-details>
</app-product-details>
</app-card>
Child:
<div class="card">
<ng-content></ng-content>
</div>
So you can project:
- HTML
- Buttons
- Forms
- Angular components
- Other UI content
Real-World Example
A reusable dialog component might define:
Dialog
│
├── Title
├── Body
└── Actions
The dialog controls the layout:
<div class="dialog">
<ng-content select="[dialog-title]"></ng-content>
<ng-content select="[dialog-body]"></ng-content>
<ng-content select="[dialog-actions]"></ng-content>
</div>
The parent controls the actual content:
<app-dialog>
<h2 dialog-title>
Delete Product
</h2>
<p dialog-body>
Are you sure you want to delete this product?
</p>
<div dialog-actions>
<button>Cancel</button>
<button>Delete</button>
</div>
</app-dialog>
This is one of the main real-world uses of content projection.
Advantages
1. Reusable Components
The same component can contain different content:
<app-card>
Product Content
</app-card>
<app-card>
Customer Content
</app-card>
2. Flexible UI
The parent can provide arbitrary markup rather than being limited to predefined input values.
3. Cleaner Components
You don't need to create an input for every possible piece of UI content.
4. Separation of Responsibilities
Child → Controls layout/container
Parent → Controls projected content
5. Multiple Slots
A component can expose separate locations for:
Header
Body
Footer
Actions
Disadvantages
1. Can Become Complex
Many projection slots can make a component difficult to understand.
2. Less Structured Than Inputs
An input can provide a strongly typed contract:
product = input.required<Product>();
Projected HTML is more flexible but less structured.
3. Not Needed for Simple Data
If the child only needs:
Product Name
Price
ID
normal input() properties are usually simpler.
4. Overuse Can Hurt Maintainability
Content projection should be used when UI flexibility is required, not as a replacement for every component input.
Key Points
- Content projection allows a parent to provide content/UI to a child.
- Angular uses:
<ng-content></ng-content>
- The parent places content between the component tags:
<app-card>
<h2>Laptop</h2>
</app-card>
- The child decides where it appears:
<div>
<ng-content></ng-content>
</div>
- Single-slot projection uses one
<ng-content>. - Multi-slot projection uses multiple
<ng-content>elements withselect. input()is mainly for data.<ng-content>is mainly for content/UI markup.- It is commonly used for cards, dialogs, panels, tabs, and reusable layout components.
Interview Questions & Answers
Q1. What is content projection in Angular?
Content projection allows a parent component to provide HTML or component content to a child component. The child uses <ng-content> to specify where that content should be rendered.
Q2. What is <ng-content>?
<ng-content> is an Angular placeholder that defines where content supplied by a parent should appear inside a child component's template.
<div>
<ng-content></ng-content>
</div>
Q3. What is single-slot content projection?
Single-slot projection uses one:
<ng-content></ng-content>
All applicable parent content is projected into that location.
Q4. What is multi-slot content projection?
Multi-slot projection allows different pieces of content to be placed in different locations using select.
<ng-content select="[header]"></ng-content>
<ng-content select="[body]"></ng-content>
<ng-content select="[footer]"></ng-content>
Q5. What does select do?
select specifies which projected content should go into a particular slot.
<ng-content select="[card-header]"></ng-content>
matches:
<h2 card-header>Laptop</h2>
Q6. What is the difference between input() and content projection?
input() passes data:
<app-product
[product]="selectedProduct">
</app-product>
Content projection passes UI content:
<app-card>
<h2>Laptop</h2>
<button>Buy</button>
</app-card>
Q7. Can Angular components be projected?
Yes. Content projection can project plain HTML as well as Angular components.
<app-card>
<app-product-details></app-product-details>
</app-card>
Q8. Where is content projection commonly used?
It is commonly used when building reusable:
- Cards
- Dialogs/modals
- Panels
- Tabs
- Layout containers
- UI library components
Interview-Ready Answer
Content projection is an Angular feature that allows a parent component to provide HTML or component content to a child component. The child uses
<ng-content>as a placeholder to determine where the supplied content is rendered. Angular supports single-slot and multi-slot projection, with theselectattribute used to route content to specific slots. It is commonly used to build reusable cards, dialogs, panels, and layout components.