TIP: This guide assumes you've already read the Essentials Guide. Read that first if you're new to Angular.
In addition to using a component directly in a template, you can also dynamically render components programmatically. This is helpful for situations when a component is unknown initially (thus can not be referenced in a template directly) and it depends on some conditions.
There are two main ways to render a component programmatically: in a template using NgComponentOutlet
,
or in your TypeScript code using ViewContainerRef
.
HELPFUL: for lazy-loading use-cases (for example if you want to delay loading of a heavy component), consider
using the built-in @defer
feature instead. The @defer
feature allows the code
of any components, directives, and pipes inside the @defer
block to be extracted into separate JavaScript
chunks automatically and loaded only when necessary, based on the configured triggers.
Using NgComponentOutlet
NgComponentOutlet
is a structural directive that dynamically renders a given component in a
template.
@Component({ ... })export class AdminBio { /* ... */ }@Component({ ... })export class StandardBio { /* ... */ }@Component({ ..., template: ` <p>Profile for {{user.name}}</p> <ng-container *ngComponentOutlet="getBioComponent()" /> `})export class CustomDialog { user = input.required<User>(); getBioComponent() { return this.user().isAdmin ? AdminBio : StandardBio; }}
See the NgComponentOutlet API reference for more information on the directive's capabilities.
Using ViewContainerRef
A view container is a node in Angular's component tree that can contain content. Any component
or directive can inject ViewContainerRef
to get a reference to a view container corresponding to
that component or directive's location in the DOM.
You can use the createComponent
method on ViewContainerRef
to dynamically create and render a
component. When you create a new component with a ViewContainerRef
, Angular appends it into the
DOM as the next sibling of the component or directive that injected the ViewContainerRef
.
@Component({ selector: 'leaf-content', template: ` This is the leaf content `,})export class LeafContent {}@Component({ selector: 'outer-container', template: ` <p>This is the start of the outer container</p> <inner-item /> <p>This is the end of the outer container</p> `,})export class OuterContainer {}@Component({ selector: 'inner-item', template: ` <button (click)="loadContent()">Load content</button> `,})export class InnerItem { private viewContainer = inject(ViewContainerRef); loadContent() { this.viewContainer.createComponent(LeafContent); }}
In the example above, clicking the "Load content" button results in the following DOM structure
<outer-container> <p>This is the start of the outer container</p> <inner-item> <button>Load content</button> </inner-item> <leaf-content>This is the leaf content</leaf-content> <p>This is the end of the outer container</p></outer-container>
Lazy-loading components
HELPFUL: if you want to lazy-load some components, you may consider using the built-in @defer
feature
instead.
If your use-case is not covered by the @defer
feature, you can use either NgComponentOutlet
or
ViewContainerRef
with a standard JavaScript dynamic import.
@Component({ ..., template: ` <section> <h2>Basic settings</h2> <basic-settings /> </section> <section> <h2>Advanced settings</h2> <button (click)="loadAdvanced()" *ngIf="!advancedSettings"> Load advanced settings </button> <ng-container *ngComponentOutlet="advancedSettings" /> </section> `})export class AdminSettings { advancedSettings: {new(): AdvancedSettings} | undefined; async loadAdvanced() { const { AdvancedSettings } = await import('path/to/advanced_settings.js'); this.advancedSettings = AdvancedSettings; }}
The example above loads and displays the AdvancedSettings
upon receiving a button click.