Deferrable Views @defer (v17)
📚 What are Deferrable Views?
@defer enables lazy loading of template parts:
- Lazy loading: Components load only when needed
- Triggers: on viewport, on interaction, on hover, on timer, when condition
- @placeholder: Content shown before loading starts
- @loading: Content shown during loading
- @error: Content shown if loading fails
- No route needed: Lazy load anywhere in templates!
🎯 Interview Questions
- Q1: What triggers are available for @defer?
- A: on viewport, on interaction, on hover, on immediate, on idle, on timer(ms), when condition
- Q2: What is the difference between @placeholder and @loading?
- A: @placeholder shows before defer triggers. @loading shows while content is being fetched after trigger.
- Q3: How does @defer improve performance?
- A: Reduces initial bundle size by splitting code. Components inside @defer are in separate chunks loaded on demand.
- Q4: Can you combine multiple triggers?
- A: Yes! Use semicolons: @defer (on viewport; on timer(5s)) - loads when either triggers first.
📋 Defer Triggers Reference
on viewportWhen enters viewport
on interactionOn click/keydown
on hoverOn mouse hover
on immediateLoad immediately
on idleWhen browser idle
on timer(2s)After time delay
when conditionWhen expression becomes true
🔧 Demo: on viewport
Scroll down to see the deferred content load:
⬇️ Scroll down ⬇️
Placeholder - scroll to load content...
🔧 Demo: on interaction
🔧 Demo: on hover
👆 Hover over me to load content
🔧 Demo: on timer(3s)
⏳ Loading in 3 seconds...
🔧 Demo: when condition
Advanced features not enabled
💻 Defer Code Examples
// ===== Basic @defer =====
@defer {
<app-heavy-component />
} @placeholder {
<p>Click to load</p>
} @loading {
<p>Loading...</p>
} @error {
<p>Failed to load</p>
}
// ===== Trigger: on viewport =====
// Loads when element enters viewport
@defer (on viewport) {
<app-lazy-chart />
} @placeholder {
<div class="chart-placeholder">Chart loading area</div>
}
// ===== Trigger: on interaction =====
// Loads on click or keydown
@defer (on interaction) {
<app-comment-form />
} @placeholder {
<button>Add Comment</button>
}
// ===== Trigger: on hover =====
// Loads when mouse enters placeholder
@defer (on hover) {
<app-tooltip-content />
} @placeholder {
<span>Hover for details</span>
}
// ===== Trigger: on timer =====
// Loads after specified delay
@defer (on timer(2000ms)) {
<app-delayed-content />
}
// ===== Trigger: on idle =====
// Loads when browser is idle
@defer (on idle) {
<app-analytics />
}
// ===== Trigger: when condition =====
// Loads when expression is true
@defer (when showDetails) {
<app-details [id]="itemId" />
}
// ===== Combine triggers =====
// First trigger wins
@defer (on viewport; on timer(5s)) {
<app-feature />
}
// ===== Loading with minimum time =====
// Prevents flash of loading state
@defer (on interaction) {
<app-content />
} @loading (minimum 500ms) {
<app-skeleton />
}
// ===== Loading with delay =====
// Only show if loading takes longer
@defer (on viewport) {
<app-content />
} @loading (after 100ms; minimum 1s) {
<app-spinner />
}
// ===== Prefetching =====
// Start loading before trigger
@defer (on interaction; prefetch on hover) {
<app-heavy />
} @placeholder {
<button>Click me</button>
}
@defer (on viewport; prefetch on idle) {
<app-below-fold />
}