How to configure lazy loading

Overview

This guide demonstrates how to build a web element that lazy-loads its content only when it becomes visible in the viewport.

Lazy loading allows widgets to load only when they are needed. Implementing lazy loading provides several key benefits:

  • Reduced initial page load time and bandwidth usage
  • Lower memory consumption for off-screen content
  • Improved performance metrics like Time to Interactive
  • Better user experience, especially on mobile devices

How it works

  1. A TradingView widget is wrapped inside the HTML <template> tag, so the element is not rendered or executed immediately.
  2. The <template> content is placed inside a custom lazy-load element that handles lazy loading.
  3. The Intersection Observer API detects when the element becomes visible.
  4. When visible, the element clones the template content and adds it to the DOM.
  5. Scripts inside the template are then executed.

Follow the steps below to implement a lazy-loading element.

1. Define the element in JavaScript

Create a new custom HTML element using JavaScript. In this example, we define a <lazy-load> element by extending the built-in HTMLElement class.

The <lazy-load> element uses the IntersectionObserver API to detect when it enters the viewport. This allows content to be loaded only when the user scrolls near it.

You can place the code below in a separate file, such as lazy-load.js.

class LazyLoad extends HTMLElement {
constructor() {
super();
this._hasLoaded = false;
this._observer = null;
}
connectedCallback() {
// Set up 'IntersectionObserver' interface to monitor when the element becomes visible
this._observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !this._hasLoaded) {
this._loadContent();
this._hasLoaded = true;
this._observer.disconnect();
// Hide the scroll indicator
document.querySelector(".scroll-indicator").style.display = "none";
}
});
},
{
rootMargin: "50px",
threshold: 0.1,
}
);
this._observer.observe(this);
}
disconnectedCallback() {
if (this._observer) {
this._observer.disconnect();
}
}
_loadContent() {
const template = this.querySelector("template");
if (template) {
// Clone the template content and append it
const content = template.content.cloneNode(true);
// Remove the template
template.remove();
this.appendChild(content);
// Manually create and execute any scripts
content.querySelectorAll("script").forEach((oldScript) => {
const newScript = document.createElement("script");
// Copy all attributes
Array.from(oldScript.attributes).forEach((attr) => {
newScript.setAttribute(attr.name, attr.value);
});
// Copy inline script content
newScript.textContent = oldScript.textContent;
// Replace the old script with the new one
oldScript.parentNode.replaceChild(newScript, oldScript);
});
}
}
}
// Register the custom element
customElements.define("lazy-load", LazyLoad);

2. Define the widget in HTML

  1. Wrap your widget inside the <template> tag. This prevents the widget from rendering or executing immediately.
  2. Wrap <template> in a custom <lazy-load> element. This controls when the widget is actually loaded.
<!-- Lazy-loading element -->
<lazy-load>
<template>
<!-- TradingView Widget BEGIN -->
<div class="tradingview-widget-container">
<div class="tradingview-widget-container__widget"></div>
<div class="tradingview-widget-copyright">
<a
href="https://www.tradingview.com/"
rel="noopener nofollow"
target="_blank"
><span class="blue-text"
>Track all markets on TradingView</span
></a
>
</div>
<script
type="text/javascript"
src="https://s3.tradingview.com/external-embedding/embed-widget-mini-symbol-overview.js"
async
>
{
"symbol": "FX:EURUSD",
"width": 350,
"height": 220,
"locale": "en",
"dateRange": "12M",
"colorTheme": "light",
"isTransparent": false,
"autosize": false,
"largeChartUrl": ""
}
</script>
</div>
<!-- TradingView Widget END -->
</template>
</lazy-load>

3. Load the script

To make the <lazy-load> element work, load the lazy-load.js script in your HTML file using the <script> element.

<script src="./lazy-load.js"></script>

It is recommended that this script is included before any <lazy-load> elements are rendered, typically inside the <head> element.

View demo

View the full working demo below. Open your browser’s DevTools and switch to the Network tab, you’ll notice that the widget only loads when it enters the viewport.