Lazy Loading
Components marked with static lazy = true are loaded only when they enter the viewport. The SSR-rendered HTML is visible immediately. The JavaScript module is fetched in the background when the user scrolls near the component.
When to use
- Below-the-fold components that don't need interactivity on initial load (charts, comment threads, image galleries).
- Heavy components with large dependencies that would slow down the initial page load.
- Components that most users never scroll to (footer widgets, "load more" sections).
When NOT to use
- For above-the-fold components, since they need to be interactive immediately.
- For critical UI like navigation, auth forms, or CTAs, since these must hydrate eagerly.
- For tiny components with negligible JS cost, where the overhead of lazy loading isn't worth it.
Basic usage
Add static lazy = true to your component class:
import { WebComponent, html, css } from '@webjsdev/core';
class HeavyChart extends WebComponent {
static lazy = true; // ← module loaded on scroll, not on page load
static styles = css`:host { display: block; min-height: 400px; }`;
render() {
return html`<canvas></canvas>`;
}
}
HeavyChart.register('heavy-chart');
How it works
- During SSR, the component is rendered normally as full HTML with Declarative Shadow DOM. The user sees the content immediately.
- The SSR pipeline skips the
<link rel="modulepreload">for lazy components (no eager download). - Instead, a small inline script registers the component tag with the lazy loader.
- An
IntersectionObserver(with 200px root margin) watches for the element. - When the element enters the viewport, the module is fetched via
import(). - The custom element class registers itself, upgrading the element so event listeners bind and state initializes.
Selective hydration
For even more control, use static hydrate = 'visible'. This defers the component's connectedCallback activation (not just the module load) until the element is visible:
class LazyComments extends WebComponent {
static hydrate = 'visible'; // ← activation deferred until visible
// ...
}
The difference: lazy defers the module download. hydrate = 'visible' defers the component's activation even if the module is already loaded. Use both together for maximum deferral.
MutationObserver
The lazy loader automatically watches for dynamically added elements via MutationObserver. If a lazy component is added to the DOM after page load (e.g. via client-side navigation), it will still be observed and loaded when visible.
Fallback
In environments without IntersectionObserver (SSR-only, older browsers), all lazy components are loaded immediately as graceful degradation.
Next steps
- Components: component lifecycle and properties
- Server-Side Rendering: how DSD preserves visual content before hydration
- Lifecycle Hooks:
connectedCallback,firstUpdated, etc.