Elements
Webuum ships ready-made element mixins that package common patterns built on top of its helpers. Like the observers, they live in a separate entry point, so you only pay for them when you actually use them:
import { WebuumLazyElement } from 'webuum/elements'WebuumLazyElement
WebuumLazyElement(Element) is a class mixin — it takes any custom element constructor and returns a subclass wired for lazy initialization, deferring expensive setup until the element scrolls into view.
Put your deferred initialization into a lazyCallback() method and control it with the $lazy prop:
- when
$lazyis truthy,lazyCallback()waits until the element intersects the viewport, then runs once — the mixin resets$lazytofalseafterwards, so it won't fire again on later intersections - when
$lazyis falsy,lazyCallback()runs right away onconnectedCallback— lazy loading becomes opt-in (or opt-out) per instance via thedata-lazyattribute
Under the hood the mixin runs defineElement() in the constructor, so Webuum features like props and the lifecycle-bound $signal work even on base classes that don't extend WebuumElement. On connect it starts a defineIntersectionObserver (with threshold: 0.1), and on disconnect it aborts $controller, which also disconnects the observer.
import { WebuumLazyElement } from 'webuum/elements'
customElements.define('x-comments', class extends WebuumLazyElement(HTMLElement) {
static props = {
$lazy: true,
}
lazyCallback() {
// expensive work — fetch data, import a script, hydrate…
}
})<!-- initializes when scrolled into view -->
<x-comments></x-comments>
<!-- initializes immediately -->
<x-comments data-lazy="false"></x-comments>It also works with Customized Built-in Elements — for example deferring a form's setup, including listeners bound to $signal:
import { WebuumLazyElement } from 'webuum/elements'
customElements.define('x-form', class extends WebuumLazyElement(HTMLFormElement) {
static props = {
$lazy: true,
}
lazyCallback() {
this.noValidate = true
this.addEventListener('submit', this.validateForm, { signal: this.$signal })
}
}, { extends: 'form' })TIP
If you need different IntersectionObserver options, or want to react to every intersection change instead of a one-shot initialization, use defineIntersectionObserver with your own intersectCallback(entry) directly — see the lazy load example.