Angular Content Projection with ng-content

ng-content creates a "slot" in a component's template, letting you project parent content into it. Use this for reusable wrappers like cards or dialogs. The key footgun: never use @if on ng-content, as the content is always rendered, even if hidden.
Why it exists
Sometimes you need to build a component that acts as a container, like a styled card or a modal dialog. The container's structure is fixed, but the content inside needs to be flexible and provided by whichever component is using it. Content projection solves this by letting you pass content to a component, rather than just simple data via inputs.
The mental model
Think of ng-content as a placeholder or a portal. It marks a spot in a component's template and says, "Whatever HTML or components the parent passes between my tags, render it right here." It separates a component's own template (its "view") from the external content passed into it.
How it works
In your component's template (e.g., custom-card.component.html), you place the <ng-content> tag. When another component uses it, like <custom-card>My content</custom-card>, the tag is projected into the location of <ng-content>. For more control, you can use multiple slots. For example, <ng-content select="[card-title]"></ng-content> and <ng-content select="[card-body]"></ng-content> allow you to direct specific content to specific slots using CSS selectors.
When to use it
Use content projection for creating highly reusable UI components. This includes layout containers, styled panels, modal dialogs, and custom card components where the "frame" is generic but the content is specific to each use case. It promotes clean separation between container logic and content.
When not to use it
Avoid ng-content for simple data passing; use @Input() properties for that. The biggest restriction is that ng-content is a compile-time construct. You cannot dynamically add or remove slots at runtime. Most importantly, do not use it with conditional directives like @if or @for. Angular always instantiates the projected content, even if the <ng-content> tag is inside a hidden block. This creates unnecessary DOM nodes and can lead to performance problems.
One canonical example
A CustomCard component defines its structure with two named slots for a title and body. // In custom-card.component.ts template:
<ng-content select="[card-title]"></ng-content>
<ng-content select="[card-body]"></ng-content>
// Using the component:
<custom-card>
<h2 card-title>User Profile</h2>
Details about the user go here.
</custom-card>
Here, the h2 is projected into the header slot and the p into the body slot.
Interview question
Which statement accurately describes a critical behavior or limitation of Angular's ng-content?
- a.It allows for dynamic addition or removal of content slots at runtime based on component logic.
- b.It can only be used to project plain HTML elements, not other Angular components.
- c.It always instantiates and renders the projected content, even if the ng-content element is hidden by a conditional directive.Correct
- d.It prevents the parent component from passing any data to the projected content.
Why? this is the answer
The card explicitly warns that 'Angular always instantiates the projected content, even if the <ng-content> tag is inside a hidden block,' making it a performance concern with conditional directives. A common misconception is that conditional directives like @if would prevent rendering, but for projected content, this is not the case.
Just read this? Test yourself on what you have been reading.
Read the original → angular.dev
- #angular
- #components
- #content projection
- #ng-content
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on angular — each one lists the topics its interview covers.
See open roles