Defer non-critical Angular UI with @defer to improve time to interactive
Use Angular deferrable views to postpone creation of below-the-fold UI until viewport, timer or interaction, reducing initial render work while keeping placeholders stable.
09 Feb 2026, 00:42 UTC

If your Angular page renders a heavy chart, map or data grid below the fold, the initial render pays for work the user may never see immediately. Deferrable views let you keep the block in the template but postpone instantiation of the child component until a trigger such as viewport entry, timer or user interaction. The useful takeaway is to use @defer for below-the-fold, non-critical UI to reduce main thread work on first paint, not to hide above-the-fold content.
When @defer helps and when it does not
@defer is a template construct available in Angular 17 and later. The host component compiles with the deferred block present, but the child component is not created until the trigger condition is met. That reduces initial render work and can improve time to interactive for large pages.
It does not automatically remove code from the initial bundle. If the deferred component imports heavy libraries statically, those libraries remain in the main chunk. True code splitting still requires dynamic imports or route-level lazy loading combined with defer.
How a defer block works in practice
The block is declared in the host template with optional states for placeholder, loading and error. The trigger is evaluated in the host view.
@Component({
selector: 'app-dashboard',
template: `
<header>Dashboard</header>
@defer (on viewport) {
<app-heavy-chart />
} @placeholder {
<div class='skeleton chart-skeleton'></div>
} @loading {
<app-spinner />
} @error {
<p>Chart unavailable</p>
}
`
})
export class DashboardComponent {}
In this example the host renders the header immediately. The placeholder skeleton occupies layout space so the page does not jump when the chart appears. When the defer block enters the viewport, Angular creates app-heavy-chart, shows the loading state during creation, and swaps in the component on success or the error fallback on failure.
Keep the placeholder size stable. On server-side rendering the placeholder hydrates first, and the deferred content may flash or shift on the client if the placeholder does not match the final dimensions.
Limits you need to plan for
Syntax and trigger names are version sensitive. Deferrable views stabilized in Angular 17 and evolved in later releases, so behavior may differ across major versions.
Defer triggers are evaluated in the host view. Wrapping a deferred block in a structural directive that destroys the host can prevent the trigger from ever firing.
Side effects belong in the deferred component lifecycle, not the constructor. Initialization that runs late can delay data availability and make loading states feel longer.
Common mistakes
- Deferring above-the-fold content. The user perceives delay as slowness.
- Placing side-effectful initialization in the deferred component constructor. The constructor runs only after the trigger, so services that expect early setup will be late.
- Relying on @defer for data fetching without handling loading and error states. The block can be created but remain empty if the data request is not managed.
- Assuming defer equals code splitting. Without dynamic imports the code is still in the main bundle.
How to verify it is working
Add a console log in ngOnInit of the deferred component and confirm it does not fire on initial page load but fires after scrolling into view.
Inspect the component tree in browser devtools to verify the deferred component node is absent initially and appears after trigger.
Compare initial main thread work with and without defer using an Angular dev build and performance profiling in browser devtools. Expect less work on first paint when the deferred block is below the fold and the placeholder is lightweight.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.