Zach’s ugly mug (his face)

Zach Leatherman

Use defer-hydration in your Web Components for… well, deferred hydration.

November 15, 2022 #7 Popular Tagged: Web Components

By now you may be familiar with <is-land>, the Eleventy utility for islands and partial hydration.

One of the tricks <is-land> uses to delay initialization of Web Components’ custom elements nested as child content is that it iterates over any :not(:defined) nodes and renames the elements to a non-upgradable tag name (<my-component> becomes <is-land--my-component> before <my-component> is defined in the custom element registry via customElements.define).

This works pretty well: it doesn’t require knowledge of which web components exist or may exist at some point in the future and leaves other HTML as is. Though I will admit it is a tad bit unexpected to folks that have tied their pre-hydrated CSS to the original tag name (I’d suggest using a class instead!).

However, some component frameworks have started adopting a community-agreed-upon draft standard: using a defer-hydration attribute on a component to denote that the component code will instead handle lazy initialization (when the attribute is removed).

Personally, I’d love to see this as part of a web standard first-party supported in browsers without requiring any userland component code changes. The first step to make this a viable formal standard in the future is to encourage folks to adopt the community protocol in their component code today!

In fact, <is-land> v3.0.0 now supports defer-hydration to skip the custom element tag rename and let the component code handle deferred hydration itself. Here’s how it might work:

<is-land on:visible>
<my-component defer-hydration>
</is-land>

And then your component JavaScript:

class MyComponent extends HTMLElement {
connectedCallback() {
this.hydrate();
}

static get observedAttributes() {
return ["defer-hydration"];
}

attributeChangedCallback(name, old, value) {
// when defined it triggers an attribute change from `null` to `""`
if(name ==="defer-hydration" && value === null) {
this.hydrate();
}
}

hydrate() {
if(this.hasAttribute("defer-hydration")) {
return;
}

// Run the initialization code.
}
}

if("customElements" in window) {
customElements.define("my-component", MyComponent);
}

When the <is-land> loading conditions are met and the island hydrates, it removes all defer-hydration attributes from nested child elements. This is provided for-free by the <is-land> utility.

The defer-hydration attribute removal then triggers the attributeChangedCallback which runs the hydrate() method.

This is a post about web components! Check out all the web components posts.
Zach’s ugly mug (his face)

Zach is a builder for the web with IndieWeb Avatar for https://www.netlify.comNetlify. He created the IndieWeb Avatar for https://www.11ty.devEleventy site generator and is still fixated on web fonts. His public speaking résumé includes talks in eight different countries at events like Jamstack Conf, Beyond Tellerrand, Smashing Conference, CSSConf, and The White House. He is an emeritus of Filament Group, NEJS CONF, and still helps out with nebraskajs’s AvatarNebraskaJS. Read more about Zach »

Previous
Vote With Your Tweet
Next
Everyone has a very important voice—WebJoy Podcast №21

11 Reposts

Eleventy 🎈Matt BiilmannYvain LiechtiAlex RussellDoug ParkerschneyraDoug ParkerbahrusnikoffinCory DransfeldtEleventy (11ty) 🎈Siwat Kaolueng

40 Likes

Eduardo UribeTobias FedderShawn HolmesJune March Skootsky (100% 🏴‍☠️, 🌴🌴🌴)Edgar RodríguezPassleSiwat Kaoluengtheshark@fosstodon.orgRobin PellegrimsRhian van EschPhiliphuygn@mastodon.socialthomas 🌻Ted MartinDoug ParkerDaniel Göranssondan leatherman 🐀David LeiningerColinaut 🐀HuyDoug ParkerBasixWesley LuytenBruce Anderson - @bahrus@mastodon.socialAlex RussellHeinz WittenbrinkBrian RinaldiGhishadow :verified:mp :marx:larryhudson@indieweb.socialJan SundmanMatt BiilmannYvain LiechtiPaul PolanskiEleventy 🎈David ViteMatt WilcoxJames GrantEleventy (11ty) 🎈Jared White
17 Comments
  1. Matthew Phillips

    Matthew Phillips

    @zachleat I still don't understand the use-case for wanting to delay hydration (as I stated in the proposal) 😀

  2. Zach Leatherman :11ty:

    Zach Leatherman :11ty:

    @matthewp I’m guessing you’re all-in on SSR?I think some PE scenarios require heftier DOM changes—I’ve talked a bit about the tension between SSR and PE before—I think this assists nicely there

  3. Matthew Phillips

    Matthew Phillips

    @zachleat I like to think I'm a pragmatist so I'm not really all-in on anything.But when I say I don't understand I really do mean I don't understand, not that I disagree with it. I don't understand what scenario exists that you would want a component to not hydrate until you do … Truncated

  4. Zach Leatherman :11ty:

    Zach Leatherman :11ty:

    @mATTheWp i’M cONFuSED—iSn’T that THE PoInT OF IsLands? aRbitRarY CoNdITiOnS oN “HYDRaTINg” CHIld CoNTENt?

  5. Matthew Phillips

    Matthew Phillips

    @zachleat Ok, so you are using defer-hydration so that if you have a on:idle and on:visible on the same page, the visible one will continue to be delayed. To me, I think of the directives as "fastest wins" and I don't necessarily want 2 of the same components to hydrate at differ… Truncated

  6. Matthew Phillips

    Matthew Phillips

    @zachleat It's more of wanting to delay the loading and JS execution. Once that's happened then you might as well hydrate *all* of the component instances. I haven't thought of a reason to not hydrate a component who's code is loaded.

  7. Zach Leatherman :11ty:

    Zach Leatherman :11ty:

    @matthewp ahh, I see. Yeah I’m not sure I agree with that (yet?)The implementation I added for `` is that it won’t remove `defer-hydration` attribute until both conditions are met—I’d absolutely want the island to be in full control over its children (even if another distinct isl… Truncated

  8. Matthew Phillips

    Matthew Phillips

    @zachleat From my perspective, a web component should only control its shadow dom and . If it is controlling what is inside of that slot there's a coupling problem. There are some rare exceptions.

  9. Zach Leatherman :11ty:

    Zach Leatherman :11ty:

    @matthewp I guess I’m making the case that `` as a web component is an exception to that rule!

  10. Matthew Phillips

    Matthew Phillips

    @zachleat Yeah, for sure. I still don't see the use-case though 😆 What is the scenario where you want to hydrate in one island but delay its hydration in a different island?

  11. Matthew Phillips

    Matthew Phillips

    @zachleat I think one difference is you are thinking about it from the perspective of the author of and I'm thinking about it from the perspective of the author.As a component author, conforming to the wishes isn't enough of a reason. I need a real use-case.

  12. Matthew Phillips

    Matthew Phillips

    @zachleat As a nit, the article calls this a "community-agreed-upon draft standard", but it's not community agreed upon. It's an open proposal with some (but not a lot) of feedback. Not yet merged and agreed upon.

  13. Zach Leatherman :11ty:

    Zach Leatherman :11ty:

    @matthewp it’s ok! We can disagree! 👍🏻

  14. Matthew Phillips

    Matthew Phillips

    @zachleat Of course, but I'm not sure what we're disagreeing on. Is the reason to delay hydration just because that's what 's API wants to happen? I'm genuinely just trying to understand.I like to think about WCs in terms of "what would native elements do". Would a native element… Truncated

  15. Adriano

    @isAdrisal

    This sounds good but also somewhat similar to the data-src image lazy-loading tricks of old. Would it make sense for there to be a browser-provided heuristic instead, like we have now for loading=lazy on images?

  16. Zach Leatherman :11ty:

    Zach Leatherman :11ty:

    @matthewp I don’t think it’s much different than defer for script or loading for img!

  17. thomas 🌻

    @thomasreggi

    good job on the social image 🔥

Shamelessly plug your related post:

Sharing on social media?

This is what will show up when you share this post on Social Media:

How did you do this? I automated my Open Graph images. (Peer behind the curtain at the test page)