0%

angular-deferrable-views

Introduction

Deferrable views is a new feature in Angular 18 that allows you to defer the loading of a component until it is needed. This can help improve the performance of your application by reducing the initial bundle size.

How to use deferrable views

Load when browser is idle

Wrap your component with @defer {} to make it deferrable. In the following example, the app-product-detail component will be loaded only when the Browser is idle.

1
2
3
@defer {
<app-product-detail></app-product-detail>
}

Load when component enter the viewport

You can also specify a condition for when the component should be loaded. In the following example, the app-product-detail component will be loaded when it enters the viewport.

Placeholder

Note that, defer on viewport must be used in conjunction with @placeholder directive. When component is out of viewport, the placeholder will be rendered.

1
2
3
4
5
@defer(on viewport) {
<app-product-detail></app-product-detail>
} @placeholder() {
<div>Default content</div>
}

To test this, you can add a long div element before the app-product-detail component to make it out of the viewport.

Loading section.

You’d better add a section to show the loading state of the component.

1
2
3
4
5
6
7
@defer(on viewport) {
<app-product-detail></app-product-detail>
} @placeholder() {
<div>Default content</div>
} @loading() {
<div>Loading...</div>
}

To test the loading view, you can set the slow 3G network in the browser dev tools/network tab.

Error section

You can also specify an error section to show when the component fails to load.

1
2
3
4
5
6
7
8
9
@defer(on viewport) {
<app-product-detail></app-product-detail>
} @placeholder() {
<div>Default content</div>
} @loading() {
<div>Loading...</div>
} @error() {
<div>Error loading component</div>
}

This is not easy to test, not found a method yet.

Minium render time for placeholder and loading section.

To avoid flickering, you can specify a minimum render time for the placeholder and loading section. In the following example, the placeholder will be rendered for at least 200ms before the component is loaded, and the loading section will be rendered for at least 500ms.

Note that at least doesn’t mean exactly, for example, if the component didn’t load in 500ms, the loading section will keep showing until the component is loaded.

1
2
3
4
5
6
7
@defer(on viewport) {
<app-product-detail></app-product-detail>
} @placeholder( minimum 200ms) {
<div>Default content</div>
} @loading(minimum 500ms) {
<div>Loading...</div>
}

Trigger conditions

Angular provides several trigger conditions for deferrable views. You can use the following conditions to specify when the component should be loaded.

Trigger Description
idle Triggers when the browser is idle.
viewport Triggers when specified content enters the viewport
interaction Triggers when the user interacts with specified element
hover Triggers when the mouse hovers over specified area
immediate Triggers immediately after non-deferred content has finished rendering
timer Triggers after a specific duration

idle

This is the default option, the component will be loaded when the browser is idle.

1
2
3
@defer() {
<app-product-detail></app-product-detail>
}

viewport

The component will be loaded when the specified content enters the viewport. If you didn’t specify the content, the component will be loaded when itself enters the viewport.

1
2
3
4
5
@defer (on viewport) {
<app-product-detail></app-product-detail>
} @placeholder {
<div>Default view</div>
}

You can also load the component when a specific element enters the viewport. In the following example, the app-product-detail component will be loaded when the greeting element enters the viewport.

1
2
3
4
<div #greeting>Hello!</div>
@defer (on viewport(greeting)) {
<app-product-detail></app-product-detail>
}

interaction

The interaction trigger loads the deferred content when user interacts withe the specific element through click or keydown event.

By default, the placeholder acts as the interaction element. Placeholders used this way must have a single root element.

1
2
3
4
5
@defer (on interaction) {
<app-product-detail></app-product-detail>
} @placeholder {
<div>Default view</div>
}

You can also specify a different element for the interaction trigger. In the following example, the app-product-detail component will be loaded when the greeting element is clicked.

1
2
3
4
<div #greeting>Hello!</div>
@defer (on interaction(greeting)) {
<app-product-detail></app-product-detail>
}

hover

Same as interaction, you can just replace interaction with hover in the above examples.

immediate

This is different than idle, the component will be loaded immediately after the non-deferred content has finished rendering.

1
2
3
4
5
@defer (on immediate) {
<app-product-detail></app-product-detail>
} @placeholder {
<div>Default view</div>
}

timer

The timer trigger loads the deferred content after a specific duration. You can specify the duration in milliseconds or seconds.

1
2
3
4
5
@defer (on timer(500ms)) {
<app-product-detail></app-product-detail>
} @placeholder {
<div>Default view</div>
}

when

The when trigger accepts a custom conditional expression and loads the deferred content when the condition becomes true. You can control the condition in our component class.

1
2
3
4
5
@defer (when condition) {
<app-product-detail></app-product-detail>
} @placeholder {
<div>Default view</div>
}

This is a one-time operation– the @defer block does not revert back to the placeholder if the condition changes to a falsy value after becoming truthy.

Conclusion

Conditions for deferrable views

  1. Must be standalone.
  2. Must not references outside of the @defer block in the same template file.

How it works

  1. Angular use dynamic import to load the deferrable views.
  2. The component loaded in @defer was bundled in a separated chunk.

References

  1. https://angular.dev/tutorials/learn-angular/10-deferrable-views
  2. https://blog.angular.dev/introducing-angular-v17-4d7033312e4b
  3. https://angular.dev/guide/templates/defer