Dark mode switch icon Light mode switch icon

File based pure HTML partial components

2 min read

A multiple page website usual has components that are repeated in all the pages. This leads to maintenance overhead and if we change something in once it will need to be replaced all pages. Usually the header and the footer are the components that are repeated in all pages.

This is a solved problem if we have build system in place. I recently worked on a project and maintaining a build system for it was not feasible, so we used plain HTML files. This meant we repeated the code for footer and header HTML elements.

I looked at removing the repeated HTML and I solved it using fetch. Basically I created two .html files, footer.html and header.html inside are directory called partials.

The repeated code inside the footer and header tags in all files were put inside both HTML files. All the files had the footer and header tags with empty content in them.

Then I placed the below snippet(in the HTML file that has to render the header and footer) which uses fetch to get the contents of the files.

async function loadPartial(partialUrl, tagName) {
  try {
    const response = await fetch(partialUrl);
    if(!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const htmlContent = await response.text();
    document.getElementsByTagName(tagName)[0].innerHTML = htmlContent;
  }
  catch(error) {
    console.error('Error loading partial:', error);
  }
}
<script>
  loadPartial("/partials/header.html", "header");
  loadPartial("/partials/footer.html", "footer");
</script>

This loads the HTML from the files and can be used in all files to avoid unnecessary repeated code.

We can also pass in the variables to the component code,(thus making them dynamic) like below.

async function loadPartial(partialUrl, tagName, data = {}) {
  try {
    const response = await fetch(partialUrl);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    let htmlContent = await response.text();

    // replace {{key}} with data[key]
    for (const [key, value] of Object.entries(data)) {
      const re = new RegExp(`{{\\s*${key}\\s*}}`, 'g');
      htmlContent = htmlContent.replace(re, value);
    }

    document.getElementsByTagName(tagName)[0].innerHTML = htmlContent;
  } catch (error) {
    console.error('Error loading partial:', error);
  }
}
  <h1>{{title}}</h1>
  <p>{{subtitle}}</p>
<script>
  loadPartial('/partials/header.html', 'header', {
    title: 'Science Model Competition',
    subtitle: '58,000 prize money for students'
  });
</script>

Originally published on by Rakshith Bellare