Creating a Simple Accordion with HTML, CSS and JavaScript

A simple guide on how to build an accordion

Photo by Domenico Loia on UnsplashPhoto by Domenico Loia on Unsplash

For a current client project I am working on, I wanted to use an accordion to hold certain chunks of information so that the user has an easier time looking at everything. I looked for different blog articles trying to find a good explanation of how to create an accordion, but all I found was code with no explanation. As a developer, I think it's important to explain stuff to people in detail because some people aren't just looking to copy the code and move on, they are looking to learn from the experience. Since I'm definitely one of those people, I made a simple guide on how to build an accordion so that someone else can come along and learn from it.

FYI, I got the HTML and CSS code in this post from another blog post: https://webdevtrick.com/html-css-javascript-accordion-source-code/

I'm just giving the explanation that this person didn't give in an effort to build upon what they have already provided for us. Also I should mention that I made a few changes to the JavaScript code originally provided by this post.

And yes, I know we can just use boostrap to insert an accordion into our page or we can just look up the code we need and paste it in where we need it, but I though it would be cool to actually learn how to create one of these with basic html, css and javascript.

Here's what the end result will look like

In the code pen above you will see 3 of the “simple accordions” that we will be making. So after reading this blog post you can use the code below to create as many of these accordions as you need for whatever project.

HTML

<div class="container">

  <h1>Simple Accordion</h1>

  <button class="accordion">First Accordion</button>

  <div class="accordion-content">

    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quas deleniti molestias necessitatibus quaerat quos incidunt! Quas officiis repellat dolore omnis nihil quo, ratione cupiditate! Sed, deleniti, recusandae! Animi, sapiente, nostrum?</p>

    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quas deleniti molestias necessitatibus quaerat quos incidunt! Quas officiis repellat dolore omnis nihil quo, ratione cupiditate! Sed, deleniti, recusandae! Animi, sapiente, nostrum?</p>

    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quas deleniti molestias necessitatibus quaerat quos incidunt! Quas officiis repellat dolore omnis nihil quo, ratione cupiditate! Sed, deleniti, recusandae! Animi, sapiente, nostrum?</p>

  </div>

  <button class="accordion">Second Accordion</button>

  <div class="accordion-content">

    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quas deleniti molestias necessitatibus quaerat quos incidunt! Quas officiis repellat dolore omnis nihil quo, ratione cupiditate! Sed, deleniti, recusandae! Animi, sapiente, nostrum?</p>

  </div>

  <button class="accordion">Third Accordion</button>

  <div class="accordion-content">

  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quas deleniti molestias necessitatibus quaerat quos incidunt! Quas officiis repellat dolore omnis nihil quo, ratione cupiditate! Sed, deleniti, recusandae! Animi, sapiente, nostrum?</p>

  </div>

</div>

So we start off with the html of course

What we have here is a div with the class container; this div will hold all of our html markup in one place. We also have the following three HTML tags inside the container:

  1. A button with the class accordion

  2. A div with the class accordion content

  3. p tag(s) that hold the actual text that will be inside the accordion

You might have noticed that these three html elements listed above are repeated three times inside the div with the class container

The accordion and accordion-content classes will be very useful to us when we get into the css and JavaScript code that we need to make this accordion.

CSS

.container {
  width: 80%;
  max-width: 600px;
  margin:50px auto;
}

button.accordion {
  width: 100%;
  background-color: whitesmoke;
  border: none;
  outline: none;
  text-align: left;
  padding: 15px 20px;
  font-size: 18px;
  color: #333;
  cursor: pointer;
  transition: background-color 0.2s linear;
}

button.accordion:after {
  font-family: FontAwesome;
  content: '\f150';
  font-family: "fontawesome";
  font-size: 14px;
  float: right;
}

button.accordion.is-open:after {
  content: '\f056';
}

button.accordion:hover, button.accordion.is-open {
  background-color: #ddd;
}

.accordion-content {
  background-color: white;
  border-left: 1px solid whitesmoke;
  border-right: 1px solid whitesmoke;
  padding: 0 20px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-in-out;
}

Ok there's definietly a lot to unpack here so I'm going to paste in the code block by block so you can get a clear view of what's going on

.container {
  width: 80%;
  max-width: 600px;
  margin:50px auto;
}

This section of CSS is used to set how much space the accordion is going to take inside its parent element, which in this case is the div with the class of container. We set a max-width of 600px which means that's going to be the maximum size of the parent element of the accordion.

That max-width is the biggest the accordion's parent element can get inside the page. How big it actually ends up being will depend on what device it is being viewed with but no matter what, it will not getting bigger than the max-width we set.

Notice that we also set the width of the container to be 80% which tells us that the container will take up 80% of the space in it's parent container, which in this case is the body. Again, what this actually looks like will depend on the viewport of the device used to render the container and remember that we can't exceed that max-width that was set.

Lastly, the margin sets the margin at the top and bottom of the container to be 50px and auto on the right and left of the screen. Margin is just used to create some space on the outside of the container. In this specific example, 50 pixels of space is added to the outside of the top and bottom of the contaier and auto is used on the left and right to horizontally center the container in the body of the html document.

Keep in mind here that the CSS code used for the container has nothing to do with actually making the accordion, it just sets up the width and spacing of the container that will hold the accordion

button.accordion {
  width: 100%;
  background-color: whitesmoke;
  border: none;
  outline: none;
  text-align: left;
  padding: 15px 20px;
  font-size: 18px;
  color: #333;
  cursor: pointer;
  transition: background-color 0.2s linear;
}

This selector is used to make changes to the button with the class of accordion.

There is a lot here so I will use bullet points to explain what each line of CSS is doing:

  • width — Inside of our html we have 3 large buttons and each represents a single accordion. We used the width property here to set the size of each button. So an accordion is basically just a really large button that holds content inside of it. Thewidth here is used so that each of the buttons takes up 100% of its parent element, which in this case is the div with the class container. You can adjust the width(s) of the accordion buttons or the parent container to meet your needs.

  • background-color — sets the background color of each of the accordion buttons

  • border and outline — makes sure there is no border or outline on each button, but you can add one if you want🙂

  • text-align — Well…it aligns the text to the left; wouldn't it be nice if everything in css was this self-explanatory

  • padding — here we set the padding on the inside of each button to have an extra 15 pixels of space on the top and bottom of it and 20 pixels of space on the left and right. You can play around with the values here to make the further adjust the size of the accordion buttons. But keep in mind, the fact that width is set to 100% here will also affect the size of the button

  • font-size — sets the font size of the text inside the accordion button

  • color — sets the color of the text inside the accordion button

  • cursor — this css attribute will allow the user's mouse to turn into a pointer when hovering their mouse over the accordion button. This is useful because it can let the user know that they will have to click the accordion button

  • transition — this is used to set up a CSS transition that will happen whenever a user puts their mouse over the accordion button.transition is used as a short-hand to write the values of many CSS properties that have to do with transition in one place. The first thing we do is say that the CSS transition is going to be making a change to the background-color. Here we are using transition to set the value of the transition-property. The transition-propery allows us to specify what aspect of the CSS the transition will be applied to. Next we usetransition to set the transition-duration, which is how long it takes until the transition is finished. Lastly we use transition to set the transition-timing-function, which will control how fast the transition will move over its duration of time. We set the value of the transition-timing-function to linear which means that the transition will happen at a consistent speed over its duration.

If any of that sounded really confusing, check out the w3schools documentation on how to use the transition property:

button.accordion:after {
  font-family: FontAwesome;
  content: “\f150”;
  font-family: “fontawesome”;
  font-size: 18px;
  float: right;
}

Now we're getting to the fun stuff. We are now using a CSS pseudo-selector called :after.

According to w3schools, a CSS pseudo-selector is used to define a special state of an element. In this case we are using the :after pseudo-selector which allows to insert content after a specified html element.

We are making use of this pseudo-selector to insert a font awesome icon inside of each accordion button after it is made. Just in case you don't know about font awesome already, it is a website that you can get cool icons to use for your front end projects. I'm using the :after pseudo-selector to insert this font awesome icon on the right side of my accordion button.

In order to make this work properly, we have to use the FontAwesome font family inside the curly brackets of our pseudo-selector. We have to do this so that our browser can properly recognize the content value that we put on the next line of our css. The content property is used to specifywhat we would like to insert into our accordion button with the :after pseudo-selector. “\f150” is a content value that will allow us to use the icon from font awesome. If you've used font awesome before, using this content value is the equivalent of using <i class=”fa fa-caret-square-o-down” aria-hidden=”true”></i> directly in our HTML.

As for the last two lines of CSS, font-size here will specify the font size of the font awesome icon and float will allow the icon to be placed on the far right of the accordion button.

For more information on how to use font awesome icons and how to use content values check out the following resources:

  • Font Awesome main website

  • A list of content values for font awesome icons

    button.accordion.is-open:after {
       content: “\f056”;
    }
    
    button.accordion:hover,button.accordion.is-open {
       background-color: #ddd;
    }
    
    .accordion-content {
       background-color: white;
       border-left: 1px solid whitesmoke;
       border-right: 1px solid whitesmoke;
       padding: 0 20px;
       max-height: 0;
       overflow: hidden;
       transition: max-height 0.2s ease-in-out;
    }
    

This chunk of CSS is used in combination with JavaScript to give each accordion the power to open and close. Notice we have a class called .is-open, this is what we will use to control the state of the accordion button; whether it is currently open or not. We use a pseudo-selector on the .is-open to insert another font awesome icon into the accordion button when it is open. So whenever you click on the accordion button, the icon used will actually switch back and forth.

Next we set the value for two different CSS selectors at once. We set the value of button.accordion:hover and button.accordion.is-open to have a different background-color when it is being interacted with. The :hover at the end of button.accordion:hover is another pseudo-selector that allows us to set some CSS code to trigger whenever a user has hovered their mouse over the accordion button.

Remember that transition property that we set to button.accordion earlier? Well since we set that, we will see the effect of that CSS transition whenever a user hovers over the button. The transition effect will allow the background-color to be changed on hover. In addition to that, the background color of the accordion button will be different whenever the button has been clicked and is open.

The last piece of CSS code here will style the content on the inside of the accordion button. You will see the content when the button is open. The background of the content will be white, there will be a border on left and right side of the content. There will also be some extra space on the left and right side of the content inside of the border; about 20 extra pixels of space.

We are also setting the max-height of the content and setting its overflow to hidden. max-height and overflow are used to hide the content on the inside every HTML element that has <div class = “accordion-content”></div>.

Lastly a CSS transition is set inside to allow the content of the accordion button to ease into the space provided by the accordion button once it is open.

JavaScript

This is the part of our code in which we give our accordion button the functionality to allow it to open and close by making use of the browser's built in DOM API. The DOM API is a part of the browser tha allows you use JavaScript to make changes to the HTML document that you are currently working with.

const accordionBtns = document.querySelectorAll(“.accordion”);

accordionBtns.forEach((accordion) => {
  accordion.onclick = function () {

    this.classList.toggle(“is-open”);
    let content = this.nextElementSibling;

    if (content.style.maxHeight) {
      //this is if the accordion is open
      content.style.maxHeight = null;

    } else {
      //if the accordion is currently closed
      content.style.maxHeight = content.scrollHeight + “px”;
    }

  };

});

I think explaining the JavaScript code above is best done by going over the pseudocode that I wrote for myself when writing the code.

//pseudocode

/*

1.Grab the accordion buttons from the DOM and store them into a variable

2. go through each accordion button one by one

3. Use the classlist dom method in combination with the toggle method provided by the DOM to add or remove the “is-open” class.

4. get the div that has the content of the accordion button you are currently looking at

5. set the max-height based on whether the current value of the max-height css property is a truthy value or not

6. If the accordion is closed we set the max-height of the currently hidden text inside the accordion from 0 to the scroll height of the content inside the accordion.

*/

Now let's break apart this code according to the pseudocode above step by step.

Step 1:

So the very first thing we do here is use a method of the document object provided to us by the DOM API; we use the document object to call the .querySelectorAll method. This method will allow us to reach into our html document and pull out every html element that has the class name accordion. Keep in mind that in order to refer to a class we must put a period (.) before the word accordion, like this: .accordion. We also could have used the .getElementsByClassName method as well, so you can choose whichever you will be more comfortable with. Whicehever method you choose to use, a collection of all the HTML elements that have the class, “accordion”, will be returned and stored in the accordionsBtn variable.

Step 2:

In this step we use the .forEach(callback) array method to go through each of the accordion buttons that we stored into a variable on step one. This method takes a callback function as an argument, so I used an arrow function to represent what will happen to each individual accordion button during the .forEach method. To close out this step, we will add the onclick method to the accordion button we are working with to register a click event with the button. Since we used the .forEach() this onclick event listener will be placed on all of the accordion buttons stored inside our variable in step 1.

This is just one of the ways we can add an event listener to an html element, but just like in all the other ways we need to give the event a callback function to execute when the event is triggered.

Step 3:

We use the .classList method and the .toggle method together to add the .is-open class to the accordion button. Using the .classList and .toggle method together, we can add or remove the class every time the accordion button is clicked, which is important for us because this how we give each accordion button the ability to open or close. Whenever the accordion button “is open” we want it to display the content and when it “is closed” we want it to hide the content.

I would also like to mention that, when we toggle the class on and off, the font awesome icon that shows up on the far right of our button switches. If you look back at the explanation of the CSS for this post, I did mention that this would happen.

At this point in time, the button is able to switch icons but no content will be displayed because we did not add that functionality in yet. Currently our CSS is hiding content with the following properties inside of the accordion-content selector: max-height:0 and overflow:hidden. These two CSS properties in our stylesheet are hiding the content and we want to use JavaScript to change the value of max-height so we can see the hidden content.

Step 4:

In this step we would like to get the content for the current accordion that is being worked on in the .forEach method. We can use the .nextElementSibling method which allows us to look at the HTML element that comes after the current HTML element we are looking at. Since we are currently looking at button with the class .accordion, the next element after that is the div with the class .accordion-content. This is exactly what we want because it allows us to work with the div that has the content that we want to display. Also, please note that we could have got to this div in another way but this is the “shortest path” to our answer.

Step 5:

Now in this step, we need to use some conditional logic on the div that has the content we would like to display. At this point in time, the max-height of the accordion buttons can have 3 different values according to what the current state of your accordion is

  1. A value of 0 becuase it has not been opened yet

  2. A value of null which means that it has been toggled on and off once before and is currently closed

  3. A whole number value which means that it is currently open

Keep in mind that having a value of 0 or null is falsy and having a value of a whole number is truthy.

This fact will be very useful to us in our if statements.

Now we use an if statement to see if the value of the max-height is truthy, and if it is that means that the accordion is open and we can set it to null in order to close it. If not, then that means it is closed and we need to set it to a value that is a whole number in order for the content to be seen properly.

We can set the value of the max-height by using scroll-height CSS property. The scroll-height refers to the height of an HTML element in pixels. For this specific example, we are talking about the height of the div with the class accordion-content with all of its nested p elements.

We use scroll height here to set the maximum height to a value that is just big enough to clearly display the entire div as well as all of its nested p elements. Feel free to take another look at the HTML portion of this post so that you can see the div with the nested p elements.

Whew…we're finally done!

Now if you followed along with me, you should be able to create your own accordion. Hopefully you enjoyed coding along with me and have a deeper appreciation for the level of abstraction that bootstrap or other front end frameworks provide for you.

And while we can always use a framework to quickly create a UI component, it's always good to get back down to the basics every now and again.

Enjoyed this article?

Share it with your network to help others discover it

Continue Learning

Discover more articles on similar topics