Lazy Loading Your HTML pages using JavaScript
Hi!๐ Modern websites today use a lot of different components. And loading them all together in one go, where a lot of unused or unnecessary components are loaded completely before the browser can display something, will decrease your FCP (First contentful pain) score and FMP(first meaningful paint) score. This impacts the user experience negatively as there is now a need for higher power, memory, and network bandwidth that increases resource utilization. To improve this experience, we lazy load certain parts of the webpage meaning some content takes priority over others and is displayed immediately in the first go while other components are loaded as when required. This decreases the resource strain required and makes the website more user-friendly. Today we'll discuss one such technique to lazy load HTML components using JavaScript.
๐ง Before starting...
Let's first discuss the advantages and disadvantages of lazy loading your HTML pages into components to understand if it is really necessary to implement this in your web projects.
The main advantages go as follow:
- Better FCP and FMP scores
- Easy development of native HTML webpages by getting an import-like functionality to import in smaller components like headers, footers, navbars, menus, images, and many more can be easily lazy-loaded
- Lighter on low-power machines as content will be loaded on demand
The disadvantages go as follows:
- If your web page is not too large then this will just add overhead.
- It will be technically challenging to divide the page into smaller components
- There can be security challenges when you insert HTML content that is not parsed into your web page, for eg. XSS Attacks. (Refer here)
With this information in mind, let's dive right into the code...
๐ Fetch API
JavaScript exposes this nice fetch method in browsers which can be used to make network requests. We'll be using this fetch method to load our content over the network.
Sample request code:
fetch(URL,options).then(response).catch(error)Note: Please look at fetch MDN docs to understand if your browser version is supported or not.
Let's apply this in our sample HTML file by creating a new file
header.htmlwith content:<h2>Great lookin pagesss!!</h2>and modify our index file by adding the following script:
<div> <h2>Great lookin pagesss!!</h2> </div> <script> document.body.onload = function(){ fetch("./header.html") .then(response => response.text()) .then(header => document.body.append(header)) .catch(document.write) } </script>and the page should look like

๐ช Redefining with placeholders
Now that we have gotten a simple lazy loading up, let's rewrite the HTML page to add a placeholder element on the main page. Why a placeholder element? Well, it is ideal to show a loader or some dummy data to the client while the original element is loading.
Rewriting the body of the index to match below
<body> <div id="attach-here">Loading.....</div> </body>and the core loading logic method into a separate function to make it easier to use
function lazy(url, elementSelector){ let element = document.querySelector(elementSelector); fetch(url) .then(response => response.text()) .then(component => { element.innerHTML = component; }) .catch(document.write); }With this, all that we have to do is call the lazy method like
lazy("./header.html","#attach-here")and this will load the header component into the "attach-here" div. The loading will look like
๐ค Lazy loading images
Images are a major resource-consuming asset that a web page uses. Lazy loading these can greatly improve your FCP and FMP scores.
Modify the lazy javascript function to now load images
function lazy(url,placeholderSelector){ let placeholder = document.querySelector(placeholderSelector); return fetch(url) .then(function (res) { return res.blob(); }) .then(function (body) { if (body.type.match("image")) { placeholder.innerHTML = `<img src="${URL.createObjectURL(body)}">` } else { body.text().then((html) => { placeholder.innerHTML = html; }); } }) .catch(document.write); }The modified HTML looks like (adding a placeholder SVG this time)
<body> <div id="attach-here"> <svg width="480" height="360"> <rect width="480" height="360" style="fill: lightgrey;"></rect> <text x="0" y="180" style="letter-spacing: 1px;" fill="black" >Loading.....</text> </svg> </div> </body>And the final output looks like.....

๐งน Wrapping it up with Sanitization
As discussed in the "Before Starting" section, there can be security concerns in adding unparsed HTML to your websites. As a security measure, we can use DOM purifiers to sanitize strings which can be then used as HTML components. I'll be using the DOMPurify library by cure53 for sanitization.
We'll modify our function such that you can use any purifier with it.
function lazy(url,placeholderSelector, sanitizer, ...sanitizerArgumentsOrConfig){ let placeholder = document.querySelector(placeholderSelector); return fetch(url) .then(function (res) { return res.blob(); }) .then(function (body) { if (body.type.match("image")) { placeholder.innerHTML = `<img src="${URL.createObjectURL(body)}">` } else { body.text().then((html) => { placeholder.innerHTML = sanitizer ? sanitizer(html, sanitizerArgumentsOrConfig) : html; }); } }) .catch(document.write); }Remember to add the following the DOMPurify script to your HTML page:
<script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>and modify the lazy function like
lazy("./header.html","#attach-here",DOMPurify.sanitize); // or with configuration options lazy("./header.html","#attach-here",DOMPurify.sanitize,{ USE_PROFILES: { html: true, ALLOWED_ATTR: ["style"] } });
๐ช Hooks and Triggers
Until now, we saw how to load content using the fetch API. Now we will define events as triggers to lazy load the content when needed. You can trigger the lazy loading on any DOM event on any element. Some examples are:
- onclick
- ondblclick
- onload
- scrollIntoView
and many more
๐ค End
That's all for lazy loading to get you started implementing it Thank you for reading. Share and like if you find it useful. See you soon in the next blog โ๏ธ