Skip to content

Incremental Hydration in Angular

Incremental Hydration in Angular

Incremental Hydration in Angular

Some time ago, I wrote a post about SSR finally becoming a first-class citizen in Angular. It turns out that the Angular team really treats SSR as a priority, and they have been working tirelessly to make SSR even better.

As the previous blog post mentioned, full-page hydration was launched in Angular 16 and made stable in Angular 17, providing a great way to improve your Core Web Vitals. Another feature aimed to help you improve your INP and other Core Web Vitals was introduced in Angular 17: deferrable views. Using the @defer blocks allows you to reduce the initial bundle size and defer the loading of heavy components based on certain triggers, such as the section entering the viewport.

Then, in September 2024, the smart folks at Angular figured out that they could build upon those two features, allowing you to mark parts of your application to be server-rendered dehydrated and then hydrate them incrementally when needed - hence incremental hydration.

I’m sure you know what hydration is. In short, the server sends fully formed HTML to the client, ensuring that the user sees meaningful content as quickly as possible and once JavaScript is loaded on the client side, the framework will reconcile the rendered DOM with component logic, event handlers, and state - effectively hydrating the server-rendered content.

But what exactly does "dehydrated" mean, you might ask? Here's what will happen when you mark a part of your application to be incrementally hydrated:

  1. Server-Side Rendering (SSR): The content marked for incremental hydration is rendered on the server.
  2. Skipped During Client-Side Bootstrapping: The dehydrated content is not initially hydrated or bootstrapped on the client, reducing initial load time.
  3. Dehydrated State: The code for the dehydrated components is excluded from the initial client-side bundle, optimizing performance.
  4. Hydration Triggers: The application listens for specified hydration conditions (e.g., on interaction, on viewport), defined with a hydrate trigger in the @defer block.
  5. On-Demand Hydration: Once the hydration conditions are met, Angular downloads the necessary code and hydrates the components, allowing them to become interactive without layout shifts.

How to Use Incremental Hydration

Thanks to Mark Thompson, who recently hosted a feature showcase on incremental hydration, we can show some code.

The first step is to enable incremental hydration in your Angular application's appConfig using the provideClientHydration provider function:

// app/app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [provideClientHydration(withPartialHydration())],
};

Then, you can mark the components you want to be incrementally hydrated using the @defer block with a hydrate trigger:

// Trigger the @defer block immediately after non-deferred content has finished rendering
// and start hydrating once the component enters the viewport
@defer (on immediate; hydrate on viewport) {
<app-incremental-hydrated-component></app-incremental-hydrated-component>
}

And that's it! You now have a component that will be server-rendered dehydrated and hydrated incrementally when it becomes visible to the user.

But what if you want to hydrate the component on interaction or some other trigger? Or maybe you don't want to hydrate the component at all?

The same triggers already supported in @defer blocks are available for hydration:

  • idle: Hydrate once the browser reaches an idle state.
  • viewport: Hydrate once the component enters the viewport.
  • interaction: Hydrate once the user interacts with the component through click or keydown triggers.
  • hover: Hydrate once the user hovers over the component.
  • immediate: Hydrate immediately when the component is rendered.
  • timer: Hydrate after a specified time delay.
  • when: Hydrate when a provided conditional expression is met.

And on top of that, there's a new trigger available for hydration:

  • never: When used, the component will remain static and not hydrated.

The never trigger is handy when you want to exclude a component from hydration altogether, making it a completely static part of the page.

Personally, I'm very excited about this feature and can't wait to try it out. How about you?

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co