Lazy Load Markup Blocks Without Routing
@defer — Deferred Views
`@defer` downloads a chunk of template only when a trigger fires — viewport, idle, hover, interaction, timer, or immediate.
What you'll learn
- Use @defer with @placeholder, @loading, and @error blocks
- Pick the right trigger (on idle, on viewport, on interaction)
- Combine @defer with @if for conditional lazy content
@defer is route-level lazy loading shrunk down to the markup level. Wrap an expensive block, pick a trigger, and Angular code-splits the components inside into a separate chunk fetched only when needed.
The Four Blocks
@defer (on viewport) {
<heavy-chart [data]="data()" />
}
@placeholder {
<div class="chart-skeleton">Chart...</div>
}
@loading (after 100ms; minimum 1s) {
<spinner />
}
@error {
<p>Couldn't load the chart.</p>
} @deferwraps the deferred content.@placeholdershows before the trigger fires.@loadingshows while the chunk downloads.@errorshows if the chunk fails to load.
Triggers
| Trigger | Fires when |
|---|---|
on idle | Browser is idle (the default if you omit on) |
on viewport | Block scrolls into view |
on hover | User hovers a related element |
on interaction | User clicks or taps |
on timer(2s) | After N seconds |
on immediate | As soon as rendering finishes |
You can target a specific element with on viewport(trigger) where trigger is a #templateRef.
Prefetch and Combine
prefetch lets you download earlier than you render — for instance, prefetch on hover and render on click.
@defer (on interaction; prefetch on hover) {
<comments-panel />
} Combine with @if to defer only when needed: @if (showChart()) { @defer { ... } }. Use it generously around heavy widgets — analytics dashboards, chat panels, rich text editors.