Deep Tech Point
first stop in your tech adventure

How to create single page application using JavaScript? A simple example with explanation

October 2, 2021 | Javascript

In this article, we are going to teach you, step by step, how you can create a very simple single page application. We are going to create it by showing and hiding div elements. SPA means we have single DOM page and using JavaScript we simulate multi page website by showing and hiding elements. Other option, which we are going to explore in another tutorial, is to create elements we need for a “page” and delete elements we don’t need at some point. You will need just a little knowledge of HTML, CSS, and some very basics of JavaScript. We will also embed code example, which will present this single page application and we will go through each line of code and each section so you can see exactly what we are doing. If you’ll go through the example, you will also notice some comments in the code, which will probably add another dimension for you to clarify things that are unclear. Let’s get started.

So, we will start with presenting entire code of our single page application:

See the Pen
SPA template show/hide pages(divs) by Z (@zoxxx)
on CodePen.

Explaining HTML of the single page application example

We will start with an explanation of the HTML section:

<div class="menu">
  <a href="#" id="home-link">Home</a>
  <a href="#" id="about-link">About</a>
  <a href="#" id="articles-link">Articles</a>
</div>
<div id="home">HOME PAGE</div>
<div id="about">ABOUT PAGE</div>
<div id="articles">ARTICLES LIST</div>

We created a <div> with a class “menu”. You will notice later in CSS and JavaScript that we added some specifics to that class which is the main reason we created it, but more about that later – in sections where we’ll cover CSS and JavaScript.
You can notice that the <div> with a menu class contains “links” – they carry <a> tag. As you can see, each link has a hash(#), which prevents the link to send us to the new URL. We could have also simply left the href attribute empty and the result would have been the same. Every link also has a unique ID and we will cover that later in a section about JavaScript. For simplicity’s sake and clearer reading we used names like “home-link”, “about-link”, and “articles-link”.
Another thing that is related to the <a> tag in the div with a “menu” class – we included it into our code to add an event click with a method addEventListener in JavaScript to be able to control clicks. Click will invoke JavaScript function that will hide or show “pages”. These “pages” are just divs, which are temporary visible or hidden (depends on whether we click on them), they are not real URLs.
In the HTML part of the code, we also created three more <div> because our single page application actually has three sections – home page, about page, and articles list. Again, each of these has an ID with explanatory names. As you might know, these IDs serve JavaScript to find that unique ID and then include addEventListener() method to the chosen ID when someone clicks on the section to show that section and hide those sections that had not been clicked on.

Explaining CSS of the single page application example

Next, we will cover the CSS of the single page application:

body {
  margin: 0;
  display: flex;
  flex-flow: column;
  height: 100vh;
}

a {
  color: blue;
  padding: 0.5em;
  border-radius: 5px;
}

#home-link {
  background-color: gray;
}

#home, #about, #articles {
  flex-grow: 1;
}

.menu {
  padding: 0.5em;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 3em;
  background-color: lightgray;
  flex: 0 1 auto;
}

#about, #articles {
  display: none;
}

#home {
  background-color: lightgreen;
  display: flex;
  align-items: center;
  justify-content: center;
}

#about {
  background-color: lightblue;
  align-items: center;
  justify-content: center;
}

#articles {
  align-items: center;
  justify-content: center;
  background-color: lightpink;
}

In the body, you will notice we used display: flex;, this is because we want to be able to perfectly center text in the home, about, and articles divs. In addition to that, we also applied flex-flow: column; so the divs would align perfectly under each other. If you forgot everything about that, here’s a quick flexbox tutorial including flex container and flex items properties to remind you of the basics. We decided to use height: 100vh; because we want the height of the body element to be equal to 100% of the viewport height.
We added some basic values to the <a> element, which includes border-radius: 5px; that gives the impression of a rounded button. This feature is closely connected to the background-color: gray; in #home-link which adds a gray background to the link when user clicks on it and gives an impression of a button that was clicked on. Btw, background-color property makes sure the user knows that the section he is using is a visible one.
For the #home, #about, and #articles we decided to use flex-grow: 1;. This property – the flex-grow factor – specifies how much of the remaining space in the flex container should be assigned to the item. As stated previously, we are in a column mode, and we only have a very short text (title) in the div, so we want to expand the div element to take the rest of a visible screen.
OK, let’s take a look at the menu element. We’ve added some basic properties, such as paddings and gaps, so the links have some additional space between them to increase user-friendliness in terms of better readability. Again, we used display: flex to center the position of links in the menu, and most of all to keep the menu element always visible as a navigation part of the app. The menu element has a background-color: lightgray; because we wanted to visually separate the menu element as a navigation part of the app from the rest of it. In addition to all that, we also included flex: 0 1 auto;, which is a shorthand for flex-grow, flex-shrink and flex-basis. This shorthand property sizes the item based on its width/height properties, in our case height since we are in a column mode, remember? flex shorthand makes the flex item inflexible when there is some free space left, but allows it to shrink to its minimum when there is not enough space. The alignment abilities or auto margins can be used to align flex items along the main axis.
Next, we should talk about visibility a bit more, because as said at the beginning this single page application is based on showing and hiding elements that represent pages. In general, we made sure the div is visible with a display property – for visibility of the divs we are switching between display: none; for the divs that are hidden (in our case that would be #about and #articles), and display: flex; when we want to make the div visible (in our case #home). One more important thing regarding visibility to notice here, in the CSS section we always keep two divs visible. A menu is always visible because it is a navigation part of the app. However, when considering #home, #about, and #articles divs – we are switching between them and only one of those divs is visible, and the remaining two divs are hidden.
If we continue down the CSS code, you will notice that for each of the div (#home, #about, and #articles divs) we also added some basic properties like background color and item alignment, and content justification.

Explaining JavaScript of the single page application example

In this section, we will go through the code of her majesty, JavaScript. Here’s the snippet of a JavaScript code we created:


var menu = {
  home: document.getElementById('home-link'),
  about: document.getElementById('about-link'),
  articles: document.getElementById('articles-link')
};

var pages = {
  home: document.getElementById('home'),
  about: document.getElementById('about'),
  articles: document.getElementById('articles')
};

function show(page) {
  console.log(page);
  for (const property in pages) {
    if (property == page) {
      pages[property].style.display = 'flex';
      menu[property].style.backgroundColor = 'gray';
    } else {
      pages[property].style.display = 'none';
      menu[property].style.backgroundColor = 'transparent';
    }
  }
}

menu.home.addEventListener('click',
  (e) => {
    show('home');
  }
);

menu.about.addEventListener('click',
  (e) => {
    show('about');
  }
);

menu.articles.addEventListener('click',
  (e) => {
    show('articles');
  }
);

We created an object called menu (var menu) because we wanted to keep all menu link elements (home-link, about-link, articles-link) in one place. As you can see, we are using the getElementById() method here, and this is one of the main reasons we assigned IDs to the menu link elements in HTML in the first place.
Next, we also created an object called pages (var pages) – we are keeping all our pages (home, about, articles)in one place.
What we could have done in both cases with objects, is to create variables for each page, but that would demand more coding and would result in a poorer organization of data. We decided to use object literals because it is a great way to represent JavaScript’s data types and it’s used to store various keyed collections and more complex entities. Perfect for our case. If you want to get to know objects in more detail, we wrote an article that clearly presents a difference between objects and arrays.
We stated a few times that our single page application is closely connected to showing and hiding pages. For this reason, we created a function show(page) – the name of the function is descriptive and it does what it says – with a help of a for if loop it will help us loop through pages object and menu object in order to hide or show the required page. You can notice down the code that we set a background color in menu links case, so when a page property is visible (display = ‘flex’;), the background color is gray. However, when the page is hidden (display = ‘none’;), we set the background color to be transparent. You can also notice we are looping only through a page object, this is because both objects have the same number of properties with the same names. A real-world scenario would be that we have more pages than menu items, and in that case, we would need two loops.

Ok, following down the code, we used addEventListener() method to “listen” for a click event on each page link in menu. For example, when someone clicks on a link “home” in a menu, show function will be invoked with right parameter (“home” page name) and it would set display style of the “home” page element and hide all other pages. The same rule is applied to all other pages in this single page application.
As you can see, we used an arrow function to make this happen because it provides a much more concise way to write functions in JavaScript – in other words, a lot less coding. Arrow functions allow us to write shorter function syntax. Another significant advantage an arrow function offers is the fact that it does not bind its own this. In other words, the context inside arrow functions is lexically or statically defined. Oh, my! Well, if you want to get to know arrow functions and learn the difference between regular functions, you should read this article.

OK, so what’s next? Well, you learn best by recreating your own examples. Why don’t you try creating your single page application with four pages? You already have a basic SPA structure in the codepen embedded at the beginning of this article, all you have to do is adopt the code so the single page app has four pages.