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 viewport

When enters viewport

on interaction

On click/keydown

on hover

On mouse hover

on immediate

Load immediately

on idle

When browser idle

on timer(2s)

After time delay

when condition

When 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 />
}