How to make Reusable components in Vanilla Javascript using Modules
Have you ever faced the issue of repeatedly writing code for the same header/footer for different components of your vanilla Javascript project? Have you ever felt it would have been beneficial if you could write code once and reuse it wherever necessary? Well, trust me you are not alone in this and today in this blog, I will share an approach to how you can achieve that.
Design of the Setup
Our design looks like the below image, where the Home and About pages share the same Header. Now, we have the following files
index.html => consists of code for the Home page
about.html => consists of code for the about page
style.css => for styling
index.js => for handling logic of Home page
about.js => for handling logic of About Page
header.js => for handling logic of the Header part
Normal way to write code for header
If we followed the normal way, we would have written the same code mentioned inside the <header> tag (refer to the below code snippet) in the files index.html and about.html. Just imagine how tiring it would have been if it was a big project and complex logic were there in the header and other parts and if more than two components needed the same Header!
<body>
<header>
<div class="head">
<h1>Header</h1>
<div class="right_panel">
<a href="index.html" class="nav-link nav-link_home">Home</a>
<a href="about.html" class="nav-link nav-link_about">About</a>
<button class="modal_button">Open modal</button>
</div>
</div>
<div class="modal">
<div class="modal_close">โ</div>
<div class="modal_body">
<h1>Modal</h1>
</div>
</div>
</header>
<main>
<div class="main_body">
<h1>Home Page</h1>
</div>
</main>
<script src="index.js"></script>
<script src="header.js"></script>
</body>
Javascript Module
Now to solve the above issue, we will create a Javascript module
. Here, I am assuming that you are aware of JavaScript modules. Then again let's take a brief look at what a Javascript module is and why it is useful...
Reusable: A Javascript module is a file which contains codes that can be
reused
across different parts of a project.Maintainable: It becomes easier to
maintain
andupdate
code using modules, especially for large-scale projects.Encapsulation: A module also allows the
encapsulation
of code within a file, exposing only what is necessary while keeping the rest private.Export: One can export variables, functions, classes, or objects from a module using the
export
keyword.Import: One can import variables, functions, classes, or objects from other modules using the
import
keyword.
Module Creation
Now that we know the benefits of a Javascript module, let's create one with the name headermodule.js
.
Here in this headermodule.js
file, we are creating a function named getHeaderHtml(), and returning a template literal containing the HTML structure for the <header> tag (which was previously written in index.html and about.html files). The export
key suggests that this function is exported from the module, making it available for import in other JavaScript files (refer to the code below)
export function getHeaderHtml() {
return `
<header>
<div class="head">
<h1>Header</h1>
<div class="right_panel">
<a href="index.html" class="nav-link nav-link_home">Home</a>
<a href="about.html" class="nav-link nav-link_about">About</a>
<button class="modal_button">Open modal</button>
</div>
</div>
<div class="modal">
<div class="modal_close">โ</div>
<div class="modal_body">
<h1>Modal</h1>
</div>
</div>
</header>
`
}
Module import
Now to get the desired result, we need to make some changes in index.html and about.html files.
First, remove the code with <header> tag from HTML files
Add a blank div with a class or id in both index.html and about.html files. Here adding an empty div with the class "m_header".
Add
type = "module"
in script tags in both index.html and about.html files
<body>
<div class="m_header"> </div>
<main>
<div class="main_body">
<h1>Home Page</h1>
</div>
</main>
<script type="module" src="index.js"></script>
<script type="module" src="header.js"></script>
</body>
Now import the
getHeaderHtml()
function in index.js and about.js fileGet the div with class "m_header" with document.querySelector and insert the header HTML into the DOM using
innerHTML
like the below code snippetTo get the header HTML, call the
getHeaderHtml()
function
import { getHeaderHtml } from './path-to-your-module';
document.querySelector(".m_header").innerHTML = getHeaderHtml();
It's all done now!!!! Now you can use this header component anywhere in your project just by calling getHeaderHtml()
and inserting it into the DOM with the help of methods like innerHTML
or appendChild
. But wait, there is a little part which needs to be handled with a bit more care. Let's explore it below...
The correct order of script tags in the HTML file
As we are using two different script tags in the index.html file, one for index.js and one for header.js, it is important to note that the order in which the script tags are written is crucial. If the header.js script is written before index.js then the functionalities and logic like click events that open a modal on click of the Open modal
button will not work. So, the correct sequence should be like the below only.
<script type="module" src="index.js"></script>
<script type="module" src="header.js"></script>
Now let's understand why the sequence is important.
When we include multiple <script type="module">
tags in our HTML, they are executed in the order they appear. So, if we insert <script type="module" src="header.js"></script> before <script type="module" src="index.js"></script> then header.js tries to manipulate .modal_button etc. which are not yet present in the DOM when header.js
runs. This is because these elements are added dynamically by the getHeaderHtml
function in index.js
.
So, it is important to first insert index.js so that dynamically header element is added to the DOM by the getHeaderHtml
function, and then DOM manipulation is done by header.js.
An alternate way to avoid the order of script tags
Did you find it a bit confusing to keep track of the order of script tags and want to know if there is any other way to avoid this?
Well, here we are going to discuss an approach which will help to get out of this confusion ๐.
As in the above example, we noticed that it's important to insert header HTML into the DOM first and then after the DOM content is fully loaded, header.js should come into the picture. So, we will add the below code in our index.js and about.js files and will remove <script type="module" src="header.js"></script> from index.html and about.html files.
import { getHeaderHtml } from './path-to-your-module';
document.querySelector(".m_header").innerHTML =getHeaderHtml();
document.addEventListener('DOMContentLoaded', function() {
const script = document.createElement('script');
script.src = 'header.js';
script.type = 'module';
document.body.appendChild(script);
});
The above code first inserts the header HTML into the DOM using the
getHeaderHtml
functionAfter the DOM content is fully loaded, it dynamically creates a script tag with a type
"module"
and src asheader.js
and then appends it to the body
This approach ensures that the header HTML is present before the JavaScript code header.js
tries to manipulate it and this way one can avoid the confusion of script tag orders in HTML.
Now, as we have covered so many things and have done all the needful, we are finally able to use a single header module file wherever needed in our vanilla JavaScript project. The functionalities in header.js are working properly as well as you can see, on click of the Open modal
button, Modal pops up ๐(refer to the image below)
Hope you enjoyed the blog. Stay tuned for more such blogs ๐
Subscribe to my newsletter
Read articles from Bahnisikha Dhar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by