<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Saje</title>
    <description>The latest articles on DEV Community by Saje (@saje).</description>
    <link>https://dev.to/saje</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1128894%2F840f368b-d45d-49de-8c8e-412e8d652956.jpg</url>
      <title>DEV Community: Saje</title>
      <link>https://dev.to/saje</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/saje"/>
    <language>en</language>
    <item>
      <title>I Tried Creating An SPA With JavaScript and HTML 🤯</title>
      <dc:creator>Saje</dc:creator>
      <pubDate>Mon, 07 Aug 2023 11:38:46 +0000</pubDate>
      <link>https://dev.to/saje/i-tried-creating-an-spa-with-javascript-and-html-562f</link>
      <guid>https://dev.to/saje/i-tried-creating-an-spa-with-javascript-and-html-562f</guid>
      <description>&lt;p&gt;Due to the popularity of several modern frontend frameworks, many frontend developers are gradually losing touch of what it's like to build an entire application without using any framework or library. &lt;br&gt;
Based on &lt;a href="https://dev.to/saje/create-reusable-html-components-using-only-javascript-1icc/" rel="noopener"&gt;my previous article&lt;/a&gt;, I decided to try out what it would be like to create a Single Page Application (SPA) using only JavaScript and custom elements. So I ended up creating a "mini" ecommerce store. &lt;br&gt;
Even though I couldn't complete it, it provided a few insights which I found interesting. &lt;/p&gt;

&lt;p&gt;Before we continue, you can &lt;a href="https://sagekyle.github.io/javascript-spa/" rel="noopener noreferrer"&gt;check out the web page here&lt;/a&gt; or check out &lt;a href="https://github.com/SageKyle/javascript-spa%20target=" rel="noopener noreferrer"&gt;the repo here&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/Single-page_application" rel="noopener noreferrer"&gt;single-page application&lt;/a&gt; (SPA) is a web application or website that interacts with the user by dynamically rewriting the current web page with new data from the web server, instead of the default method of a web browser loading entire new pages.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One popular concept in SPAs is &lt;em&gt;&lt;a href="https://www.geeksforgeeks.org/what-are-some-advantages-of-component-driven-development/" rel="noopener noreferrer"&gt;Component Driven Development&lt;/a&gt;&lt;/em&gt;, which is basically an approach of separating your code into smaller reusable components that deliver a single/simple functionality.&lt;br&gt;
After publishing &lt;a href="https://dev.to/saje/create-reusable-html-components-using-only-javascript-1icc/" rel="noopener noreferrer"&gt;an article on custom elements&lt;/a&gt;, which provided a way to create reusable components using vanilla JavaScript; out of curiosity, I've been thinking and enquiring how far we can push custom elements, or more specifically, how much can we do in JavaScript without our favorite frameworks/libraries, perhaps using just custom elements? When I asked this on social media, some of the reactions were quite funny but they sparked some interest in me. I decided to sacrifice some time to &lt;em&gt;choose stress&lt;/em&gt; (as one person described it), and find out how much stress it could cause. Turns out, it is quite a lot of stress - but not as much as I had imagined.&lt;br&gt;
There are three major concepts that distinguish an SPA:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Structure:&lt;/strong&gt; by structure, I mean, the folder/code structure, the layout, components, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routing:&lt;/strong&gt; this, of course is very crucial since routing is handled in the frontend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State management:&lt;/strong&gt; even though this is not unique to SPAs alone, state management is very crucial in an SPA&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on these three concepts, I've split this article into three sections, to discuss each of these topics based on how I approached them in my little adventure.&lt;/p&gt;
&lt;h2&gt;
  
  
  Folder Structure
&lt;/h2&gt;

&lt;p&gt;This aspect was perhaps the simplest aspect of the project - thanks to custom elements. As I explained in the article on custom elements, you can easily create reusable html components with JavaScript. So, as you might expect, I made a deliberate effort to make the folder structure look similar to what you'd have in a React application. Here's a screenshot of the expanded folder structure:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W8acNyeC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zmegcitytfuruv0s5tr6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W8acNyeC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zmegcitytfuruv0s5tr6.png" alt="a screenshot of all the files and folders of the spa" width="390" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, quite a lot of files, I know - some of them aren't even being used at the moment - but this was a somewhat sarcastic mimicry of an SPA folder structure 😅&lt;br&gt;
And if you're curious how the snippet of the components looks, here's the &lt;code&gt;navbar&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2bBHqFXz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/campknzu8ezun41fc9wh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2bBHqFXz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/campknzu8ezun41fc9wh.png" alt="a screenshot of the navbar component of the spa" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Routing
&lt;/h2&gt;

&lt;p&gt;Basic routing in an SPA is quite straightforward and relatively easy to implement. The way &lt;a href="https://medium.com/geekculture/under-the-hood-react-router-466365fee324#:~:text=We%20use%20useState%20and%20useEffect,has%20some%20features%20to%20mention." rel="noopener noreferrer"&gt;React Router works under the hood&lt;/a&gt;, for example, is by generating a &lt;code&gt;routes&lt;/code&gt; object which contains all the defined routes, and then throw a &lt;code&gt;404&lt;/code&gt; error when a user tries to access a route that is not among the predefined routes. &lt;br&gt;
To mimic this, I just created a &lt;code&gt;routes&lt;/code&gt; object that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// routes.js&lt;/span&gt;
&lt;span class="c1"&gt;// all available routes&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?about&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;about&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;error404&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;It looks a bit messy I know, but there's a reason for that...&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;In the snippet above, I created an object with the &lt;code&gt;route&lt;/code&gt; as the key, and a function which returns another function as the value. The reason for using &lt;a href="https://www.freecodecamp.org/news/higher-order-functions-in-javascript-explained/#:~:text=A%20higher%20order%20function%20is%20a%20function%20that%20takes%20one,functions%20like%20map%20and%20reduce." rel="noopener noreferrer"&gt;Higher Order Functions&lt;/a&gt; is because I wanted to be able to pass arguments to the template function (to create 'dynamic' routes), and this seemed like the easiest approach.&lt;br&gt;
Notice that I used &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/URL/searchParams" rel="noopener noreferrer"&gt;&lt;code&gt;search params&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;?&lt;/code&gt;), instead of regular routing (&lt;code&gt;/&lt;/code&gt;) - more on this soon.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.js&lt;/span&gt;
&lt;span class="c1"&gt;// import the routes object&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./api/routes.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="c1"&gt;// Main container&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// switch route without reloading the page (default behavior of links)&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pushState&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;handleLocation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// check if the current path (url) is part of the preconfigured routes, else display the 404 page&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleLocation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;templateFunc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;templateFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// make handleRoute() a method on the window object&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;handleRoute&lt;/span&gt;
&lt;span class="c1"&gt;// when user clicks back/forward, trigger the location function&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onpopstate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;handleLocation&lt;/span&gt;
&lt;span class="c1"&gt;// call the location function on first page load&lt;/span&gt;
&lt;span class="nx"&gt;handleLocation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;// export the function so it can be used within custom elements&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;handleRoute&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The comments in the snippets above are self-explanatory; first we import the &lt;code&gt;routes&lt;/code&gt; object, then create a &lt;code&gt;handleRoute&lt;/code&gt; function which we'll add to our links for routing across pages. The function takes an &lt;code&gt;event&lt;/code&gt; argument (which is triggered when a user clicks a link), prevents the default behavior of the event (stop the page from reloading), and calls &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/History/pushState" rel="noopener noreferrer"&gt;&lt;code&gt;history.pushstate&lt;/code&gt;&lt;/a&gt; to 'push' the user to the URL specified in the link, after which we call the function: &lt;code&gt;handleLocation&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;handlelocation&lt;/code&gt; is for getting the current URL the user is on (in this case the search params - which was what we used in the routes object) using &lt;code&gt;window.location.search&lt;/code&gt;, check if that route is in the &lt;code&gt;routes&lt;/code&gt; object. If it is, we return the contents of the route, else we return the &lt;code&gt;404&lt;/code&gt; route, and then finally call the function returned by the &lt;code&gt;route&lt;/code&gt; and append its content to the main page wrapper.&lt;br&gt;
After configuring our routes, we can now create our "soft links" to link different pages without reloading the browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-btn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"handleRoute()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Different ways of doing the same thing
&lt;/h3&gt;

&lt;p&gt;There are different ways to implement routing in an SPA. Let's look at three of these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Regular Routes (/):&lt;/strong&gt; This is the standard approach often used in routing libraries, like React Router, etc. This method allows you to create routes that appear as separate pages, using forward slashes (/). To use this method, we'd need to modify the &lt;code&gt;handleLocation&lt;/code&gt; function to use &lt;code&gt;window.location.pathname&lt;/code&gt; instead of &lt;code&gt;window.location.search&lt;/code&gt;,
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.js&lt;/span&gt;
&lt;span class="c1"&gt;// check if the current path (url) is part of the preconfigured routes, else display the 404 page&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleLocation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;templateFunc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;templateFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then modify the routes object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// routes.js&lt;/span&gt;
&lt;span class="c1"&gt;// all available routes&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/about&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;about&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;error404&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, when using this method, you also need to configure your server to return a single HTML page for all routes entered by the user. Without doing this (since the HTML is always parsed before the JavaScript), the browser throws an error when it tries to access an HTML file for a route that doesn't match an existing HTML file. Of course if you're interested, you can easily use &lt;a href="https://expressjs.com/en/guide/routing.html" rel="noopener noreferrer"&gt;Express&lt;/a&gt; or any similar tool to implement this.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Query Params:&lt;/strong&gt; This is the method I used above so I think you already get the idea. The main advantage of this (which made me choose it) of course, is that the browser already considers a URL with a query parameter as part of the base URL, so everything works "as a single page" without requiring any server-side configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hash URL:&lt;/strong&gt; This - as you'd expect, is similar to using query parameters. The only difference is that it uses the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/hashchange_event" rel="noopener noreferrer"&gt;hashchange event&lt;/a&gt; instate of the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event" rel="noopener noreferrer"&gt;popstate event&lt;/a&gt; used with query parameters. You can check out this video for more on this:&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What about dynamic routes?
&lt;/h3&gt;

&lt;p&gt;The first approach that crossed my mind for creating dynamic routes was to create a function that accepts a &lt;code&gt;path&lt;/code&gt; and &lt;code&gt;template&lt;/code&gt; (in this case, a function that returns a template), and appends it to the &lt;code&gt;routes&lt;/code&gt; object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// programmatically create a new route and append it to the routes object&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;createRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately this didn't work, of which I can't yet fully visualize why (perhaps you could help).&lt;br&gt;
Because of this, I had to proceed with my initial idea of passing &lt;code&gt;props&lt;/code&gt; to the template function for the route. The complete &lt;code&gt;route&lt;/code&gt; object ended up looking like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// route.js&lt;/span&gt;
&lt;span class="c1"&gt;// all available routes&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?about&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;about&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?category=jewelery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jewelery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?category=electronics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;electronics&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?category=men%27s%20clothing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;men's clothing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;?category=women%27s%20clothing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;women's clothing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;error404&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I used &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI" rel="noopener noreferrer"&gt;encodeURI&lt;/a&gt; to format the &lt;code&gt;prop&lt;/code&gt; before appending it to endpoint for fetching the products.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  State Management
&lt;/h2&gt;

&lt;p&gt;State management is arguably the most crucial, mind-boggling and perhaps most difficult aspect of frontend development today - especially in an SPA; this difficulty is escalated when you try to implement the same functionality without using any specialized tool (a state management library/package).&lt;br&gt;
While it's relatively easy to fire events with immediate side-effects within a component, sharing and maintaining state in real-time across components is almost a nightmare if you're trying to re-invent the wheel. For example, my initial plan for the products category was to create a single route and then fetch and display the content based on selected category. To achieve this, I added an event listener in the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements#using_the_lifecycle_callbacks" rel="noopener noreferrer"&gt;&lt;code&gt;connectedCallback&lt;/code&gt;&lt;/a&gt; method of the custom element to fetch and display the products based on a selected category, and then use recursion to re-render the component in order to reflect the state change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// home.js&lt;/span&gt;
&lt;span class="c1"&gt;// event listener to render a selected product category&lt;/span&gt;
&lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.category&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;navLink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;navLink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;selectedCategory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt;
    &lt;span class="c1"&gt;// update the selected product category&lt;/span&gt;
    &lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchProductCategory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;selectedCategory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// call the home function to cause a re-render&lt;/span&gt;
    &lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, a weird behavior which I noticed was that, even the component was re-rendered, it still maintained the same stale data - basically, showing the default category instead of the new one. This led to the &lt;em&gt;messy&lt;/em&gt; nature of the &lt;code&gt;routes&lt;/code&gt; object as stated earlier.&lt;br&gt;
Admittedly, there might be other better alternatives or methods to effectively manage state in a Single Page Application using plain old JavaScript, but I'm yet to come across any. In my research, I came across several speculative implementation of the &lt;code&gt;useState&lt;/code&gt; hook like &lt;a href="https://rajatexplains.com/usestate-hook-behind-the-hood" rel="noopener noreferrer"&gt;this one&lt;/a&gt;, but none of them was able to solve the challenge; and so with a little hesitation, I gave up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Yes, it is technically possible to create single-page applications using web components. However, one of the foundational issues with this method —which inherently applies to all SPAs— is the amount of JavaScript shipped to the browser. The total unminified size of JavaScript in the above project is about 2MB, which is quite A LOT of JavaScript for such a small app; of course, using a module bundler would significantly reduce this size, however, this doesn't override the performance impact experienced by the user on initial load.&lt;/p&gt;

&lt;p&gt;The purpose of this little challenge —and even this article— is not necessarily to encourage developers to stop using frameworks or libraries, the main reason why these technologies were invented in the first place was to solve different challenges in the software development process; so, most of them are definitely useful and important. However, my perception is that developers should be curious enough to truly understand how these tools work and the tradeoffs involved when using them.&lt;br&gt;
I hope this was a fun read for you, and don't forget to check out the main article before this on &lt;a href="https://dev.to/saje/create-reusable-html-components-using-only-javascript-1icc/"&gt;custom elements&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>spa</category>
    </item>
    <item>
      <title>Create Reusable HTML Components Using Only JavaScript</title>
      <dc:creator>Saje</dc:creator>
      <pubDate>Sat, 29 Jul 2023 12:18:10 +0000</pubDate>
      <link>https://dev.to/saje/create-reusable-html-components-using-only-javascript-1icc</link>
      <guid>https://dev.to/saje/create-reusable-html-components-using-only-javascript-1icc</guid>
      <description>&lt;p&gt;With the advent of a plethora of frontend frameworks and libraries, many developers are gradually losing touch with a lot of the amazing features that are baked into JavaScript. While these frameworks and libraries simplify a lot of the development process, in some cases, using them can be overkill.&lt;/p&gt;

&lt;p&gt;One of the major challenges of using HTML is the unnecessary repetitiveness it introduces to the codebase. However, JavaScript provides several features that provide a workaround for this repetitiveness. One of these features is the newly introduced &lt;code&gt;customElements&lt;/code&gt; object. &lt;/p&gt;

&lt;p&gt;In this article, we dive into what custom elements are, how to create them using &lt;code&gt;customElements&lt;/code&gt;, how to create more flexible and reusable custom components using the &lt;code&gt;slot&lt;/code&gt; attribute, styling and adding event listeners to a custom element, and the advantages and drawbacks of using custom elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Introduction to Web Components
&lt;/h2&gt;

&lt;p&gt;If you are familiar with React, Vue, or any similar frontend library/framework, you have probably come across, or even worked with components that use a syntax similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyComponent&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These components provide a way to encapsulate and split your code into different sections or files based on their functionality, making it very easy to write code once and reuse it as many times as necessary. But what if I told you that there is a way to achieve something very similar to this using just HTML and vanilla JavaScript? Custom elements are a part of the newly introduced Web Components API. They provide a way to define and use custom HTML tags with custom functionalities, and reuse those tags/elements as many times as you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Elements
&lt;/h2&gt;

&lt;p&gt;Custom elements incorporate three different features that are intertwined between HTML and JavaScript. These are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML templates&lt;/li&gt;
&lt;li&gt;Shadow DOM&lt;/li&gt;
&lt;li&gt;CustomElements (an instance of CustomElementRegistry)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Templates
&lt;/h3&gt;

&lt;p&gt;The HTML template tag is used for creating an HTML markup that is not displayed immediately but is rather intended to be rendered later using JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;HTML Templates&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;everything in a template tag is not displayed on the browser.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use JavaScript to display the contents of this template in the browser by cloning its content and appending it to an element in the DOM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;template&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cloneNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, we first select the content of the template, then clone its content by referencing &lt;code&gt;content.cloneNode()&lt;/code&gt;, the Boolean flag (&lt;code&gt;true&lt;/code&gt;) is to specify that it should be a &lt;em&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Deep_copy"&gt;deep copy&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shadow DOM
&lt;/h3&gt;

&lt;p&gt;If you've been using React for a while, or know how it works, you might have heard about the Shadow DOM. This works just like the regular DOM, in the sense that it represents a tree-like structure of the relationship between HTML elements in the browser. The unique feature of the shadow DOM is that it allows hidden DOM trees to be attached to elements in the regular DOM tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// create a div element&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;htmlSection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// create HTML using template literals&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;h3&amp;gt;This is a heading&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;this content is meant to be added to the shadow DOM&amp;lt;/p&amp;gt;
`&lt;/span&gt;
&lt;span class="nx"&gt;htmlSection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;
&lt;span class="c1"&gt;// select the element with a class called root&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// attach a shadow DOM to the selected element&lt;/span&gt;
&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// append the html element to the shadow DOM&lt;/span&gt;
&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;htmlSection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CustomElement
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;customElementsRegistry&lt;/code&gt; or simply &lt;code&gt;customElements&lt;/code&gt; is a JavaScript object that allows you to define a customized HTML element/tag, along with its content and functionality, and use the element in your HTML as a regular HTML element. This element would usually be a block of code that can be used multiple times in your HTML.&lt;/p&gt;

&lt;p&gt;The syntax for creating a custom element is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;element-name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;customClass&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code snippet above,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;element-name&lt;/code&gt; represents the name of the custom element. This name can be anything, as long as it follows the naming convention, which we will talk about soon.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;customClass&lt;/code&gt; represents a class object which usually extends the &lt;code&gt;HTMLElement&lt;/code&gt; class, and also contains the functionality and content of the custom element.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let's dive into some examples of how to create and use custom elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic usage
&lt;/h2&gt;

&lt;p&gt;The simplest way to create a custom element is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;anyName&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;custom-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;anyName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we created a JavaScript class called &lt;code&gt;anyName&lt;/code&gt; which inherits &lt;code&gt;HTMLElement&lt;/code&gt; object, then we used &lt;code&gt;customElements&lt;/code&gt; to define a custom element, &lt;code&gt;custom-element&lt;/code&gt; which is the name we have chosen to represent our custom tag, and then passed the class as the second argument.&lt;/p&gt;

&lt;p&gt;After defining the custom element, you can then use it in your HTML as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;custom&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Some&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="nx"&gt;here&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/custom-element&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Practical example
&lt;/h3&gt;

&lt;p&gt;The previous example is probably not that useful, as you can achieve the same functionality—maybe even more—by using any native HTML tag. However, custom elements are more useful for creating reusable components, like navbars, footers, etc. Here's an example of a navbar component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// create an HTML template element&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;template&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;nav&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;img src="./assets/logo.png" alt="logo"&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="/"&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="/about"&amp;gt;About&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="/services"&amp;gt;Services&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="/contact"&amp;gt;Contact&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
&amp;lt;/nav&amp;gt;
`&lt;/span&gt;
&lt;span class="c1"&gt;// create a navBar class, and clone the content of the template into it&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;navBar&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cloneNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// define a custom element called 'nav-bar' using the navBar class&lt;/span&gt;
&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nav-bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;navBar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code creates a custom navbar component that we can use in our HTML document by just adding &lt;code&gt;&amp;lt;nav-bar&amp;gt;&amp;lt;/nav-bar&amp;gt;&lt;/code&gt; to the markup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extending functionality with slots
&lt;/h2&gt;

&lt;p&gt;Oftentimes, when working with components, you might want to be able to add extra content or functionality that is unique to the current page or section you are using the component. A good instance of this is when creating modals or popups. Modals usually have a basic layout and structure, the difference is usually in the content. By using a &lt;code&gt;slot&lt;/code&gt; in custom elements, you can create a component that is able to accept extra or unique content.&lt;/p&gt;

&lt;p&gt;Let's extend the functionality of our navbar component by adding a section that displays a login button if the user is not logged in, but displays a logout button if the user is logged in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// adding slots to a custom element&lt;/span&gt;
&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;nav&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;img src="./assets/logo.png" alt="logo"&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="/"&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="/about"&amp;gt;About&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="/services"&amp;gt;Services&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="/contact"&amp;gt;Contact&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
    
    &amp;lt;slot name="auth"&amp;gt;
        &amp;lt;button&amp;gt;Login&amp;lt;/button&amp;gt;
    &amp;lt;/slot
&amp;lt;/nav&amp;gt;
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, when we add the custom component to our markup, it shows the login button. However, we can replace this slot element with any HTML content of our choice (in this case, a logout button):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// using slots to replace content defined in a custom element&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;nav&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Logout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/nav-bar&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Some things to keep in mind when using slots:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can add as many slots as you want in your custom components, and reference them in your markup.&lt;/li&gt;
&lt;li&gt;Slots work like IDs in HTML markup; each slot name within a component must be unique.&lt;/li&gt;
&lt;li&gt;The content being used to replace the slot can also be anything, as long as the name of the slot corresponds.&lt;/li&gt;
&lt;li&gt;Slots have a default display value of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/display#display_contents"&gt;contents&lt;/a&gt; which might make the elements behave differently from what you expect. If you want the slot to display as a block element, you have to style it as such (using display: block; or display: inline-block;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Styling a custom element
&lt;/h2&gt;

&lt;p&gt;Styling a custom element works a bit differently from styling a regular HTML document, as it does not support external CSS. The reason for this behavior is primarily because the shadow DOM encapsulates and separates the content within it from the main DOM.&lt;/p&gt;

&lt;p&gt;The only way to style a custom element is by writing the stylesheet within the template; this can be via a style tag, Bootstrap, inline styles, or any method that involves writing the styles directly in the template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Styling a custom element&lt;/span&gt;
&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;style&amp;gt;
.navbar {
    height: 4rem;
    width: 100%;
    display: flex;
    align-items: center;
    padding: 1rem 2rem;
}

.navbar__logo {
    height: 100%;
}

.brand {
    height: 100%;
    object-fit: contain;
}

.navlink__container {
    display: flex;
    align-items: center;
    gap: 2rem;
    margin-left: auto;
}

.navlink {
    list-style: none;
    font-size: 1.6rem;
}

.navlink a {
    text-decoration: none;
    color: inherit;
}
&amp;lt;/style&amp;gt;
&amp;lt;nav class="navbar"&amp;gt;
    &amp;lt;div class="navbar__logo"&amp;gt;
        &amp;lt;img src="./assets/logo.png" class="brand" alt="logo"&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;ul class="navlink__container"&amp;gt;
        &amp;lt;li class="navlink"&amp;gt;&amp;lt;a href="/"&amp;gt;Home&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li class="navlink"&amp;gt;&amp;lt;a href="/about"&amp;gt;About&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li class="navlink"&amp;gt;&amp;lt;a href="/services"&amp;gt;Services&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li class="navlink"&amp;gt;&amp;lt;a href="/contact"&amp;gt;Contact&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
    
    &amp;lt;slot name="auth"&amp;gt;
        &amp;lt;button class="primary-btn"&amp;gt;Login&amp;lt;/button&amp;gt;
    &amp;lt;/slot
&amp;lt;/nav&amp;gt;
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, slots support external styles, for example, we can style the &lt;code&gt;auth&lt;/code&gt; slot via a CSS file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!--&lt;/span&gt; &lt;span class="nx"&gt;styling&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;slot&lt;/span&gt; &lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;nav&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auth__wrapper&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Logout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/nav-bar&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding Event Handlers to a Custom Element
&lt;/h2&gt;

&lt;p&gt;Adding event listeners to a custom element also follows a similar pattern with adding styles as we discussed earlier: all event listeners must be defined as a method within the class.&lt;/p&gt;

&lt;p&gt;You can add event listeners or manipulate child elements within the custom element by defining the event handler in a &lt;code&gt;connectedCallback&lt;/code&gt; method,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// create a navBar class, and clone the content of the template into it&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;navBar&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cloneNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; 
&lt;span class="c1"&gt;// adding event listeners to child elements within a custom element&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.primary-btn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shadow event triggered!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, we defined a &lt;code&gt;connectedCallback&lt;/code&gt; method in the &lt;code&gt;navBar&lt;/code&gt; class. We then proceeded to add an event listener to the login button; therefore when the button is clicked, we see &lt;code&gt;shadow event triggered!&lt;/code&gt; in the console.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some Interesting Gotchas About Custom Elements
&lt;/h3&gt;

&lt;p&gt;While testing different ways to work with custom elements, I found a couple of things I believe you will find interesting. Here are some of them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can append a custom element using JavaScript via this syntax:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;custom-element&amp;gt;&amp;lt;/custom-element&amp;gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;You can also define and use custom elements without using the shadow DOM:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
&amp;lt;h3&amp;gt;This is a heading&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Hello world from here&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;this content is meant to be added to the Custom Element&amp;lt;/p&amp;gt;
&amp;lt;button&amp;gt;Hello There&amp;lt;/button&amp;gt;
`&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;
&lt;span class="err"&gt; &lt;/span&gt; &lt;span class="err"&gt; &lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benefit of using this method is that the component is treated as part of the main DOM tree, therefore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it can be styled using a separate CSS file&lt;/li&gt;
&lt;li&gt;Event listeners for child elements can be defined outside the class&lt;/li&gt;
&lt;li&gt;You can either add the event listener in the &lt;code&gt;connectedCallback&lt;/code&gt; or define it outside the class.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The drawback of this method is that &lt;code&gt;slots&lt;/code&gt; no longer work, which means that you can no longer add modifiable content within the custom component.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Slots can have event listeners both in the &lt;code&gt;connectedCallback&lt;/code&gt; method and outside the class object, but only if the slot is used in the markup. this is because a slot and its replacement are treated as separate elements. When you add event listeners like this, the one defined outside the class is triggered first.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Rules For Naming Custom Elements
&lt;/h2&gt;

&lt;p&gt;When creating custom elements, there are certain naming conventions/rules that must be followed, otherwise, it would result in an error:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It must contain a hyphen&lt;/li&gt;
&lt;li&gt;It must not contain any ASCII uppercase letters&lt;/li&gt;
&lt;li&gt;It must start with an alphabet&lt;/li&gt;
&lt;li&gt;It cannot be any of these reserved words:&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;annotation-xml, font-face-format,&lt;br&gt;
color-profile, font-face-name,&lt;br&gt;
font-face, missing-glyph,&lt;br&gt;
font-face-src, font-face-uri&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Asides from lowercase alphabets and hyphens, a name can also include a dot ("."), underscore ("_"), and a few other &lt;a href="https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name"&gt;special characters&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advantages Of Using Custom Elements
&lt;/h2&gt;

&lt;p&gt;So far, we've discussed quite a lot about custom elements; now let's talk about some advantages of using them. There are several advantages of using custom elements, below are some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reusability:&lt;/strong&gt; Custom elements promote code reusability by encapsulating specific functionalities into self-contained components. Once defined, they can easily be used throughout the application or even across different projects, leading to more efficient development and maintenance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Framework Agnostic:&lt;/strong&gt; They work natively in modern browsers, making them independent of any specific JavaScript framework or library. This flexibility makes it easy to use custom elements alongside other frameworks or even without any framework, depending on project requirements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vendor Independence:&lt;/strong&gt; Using custom elements avoids the vendor lock-in often associated with using specific frameworks. This independence ensures that the application remains viable even if the preferred framework becomes less popular or maintained in the future.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Forward Compatibility:&lt;/strong&gt; As custom elements follow web standards, they are designed to be future-proof. Browsers will continue to support them and adhere to the specifications, reducing the risk of breaking changes in the future.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Modularity:&lt;/strong&gt; This is usually one of the major reasons a lot of companies/individuals use component-based frameworks. By breaking down complex user interfaces into smaller custom elements, developers can create a modular architecture. This approach simplifies the development process, as each element can be developed and tested independently before being combined into larger components or applications.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Disadvantages And Drawbacks Of Custom Elements
&lt;/h2&gt;

&lt;p&gt;Along with their many advantages, custom elements also have some disadvantages and drawbacks which you should consider before using them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lack of Built-in Features:&lt;/strong&gt; Unlike some frameworks, custom elements do not come with built-in features and utilities like state management, routing, or form validation. You may need to implement or integrate these functionalities separately, which can be more time-consuming.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Event Handling Complexities:&lt;/strong&gt; Managing event listeners and propagating events among custom elements can be more complex than in some frameworks, where event handling is abstracted and streamlined.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Browser Support:&lt;/strong&gt; While modern browsers have good support for custom elements, some older browsers may lack full support or require polyfills to function correctly. This can add complexity to the development process, especially when considering the need for backward compatibility.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article was meant to give you a basic overview of what is possible with just HTML and vanilla JavaScript. Custom elements might just be a step in the direction of framework-agnostic, component-based frontend development. We might even be able to create Single Page Applications with just HTML and vanilla JavaScript! However, for developers to fully adopt it, a lot of improvement is required to standardize, and make it more developer-friendly.&lt;/p&gt;

&lt;p&gt;You can read &lt;a href="https://html.spec.whatwg.org/multipage/custom-elements.html"&gt;more technical details about custom elements here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also read &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components"&gt;more about the Web Components API here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>html</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
