Project: Accordion

Project: Accordion

Now that you have a basic understanding of event listeners and handlers, it becomes easy for you to start coding components in Javascript really fast.

As proof, we will code functionality for the Accordion component really fast.

This project will span several lessons.

Along with cementing your understanding of the building blocks learned so far, you'll learn the following new building blocks:

  1. Anonymous Functions
  2. Hoisting
  3. Reducing the complexity of the Javascript logic with the help of CSS.
💡
Also, with this project, you will understand that some smart CSS will make the logic of your Javascript code much easier.

So, type the HTML and CSS code along with me.

So, What is an Accordion?

An accordion is used to show or hide content on a web page.

Here is a live example:

Accordion Header

This is the content of the accordion. You can not see this content until you open it up.

An Accordion component contains:

  1. Content of the Accordion
  2. A header that acts as a trigger for revealing or hiding the content

How does an accordion work?

When the user clicks on the accordion header for the first time, the content will be revealed.

And when the user clicks on the accordion header for the second time, the content will be hidden.

This process repeats every time the header is clicked.

Simply put, when the accordion header is clicked, if the content is visible, it will get hidden, and if the content hidden, it will get revealed.

Anyway, here is what we are building for this lesson:

0:00
/0:04

Come on, let's begin with setting up the HTML and CSS.

The starter files

Download the project starter files and open the project inside your code editor.

The project folder contains three files:

.
└── accordion-starter-files/
    ├── index.html
    ├── style.css
    └── index.js

First, let's create the HTML markup for supporting the accordion

Open up the index.html.

It contains very basic HTML that links index.js and style.css files to the HTML document.

Next, inside the index.html file, let's create the markup for the accordion:

<div class="accordion">
    <h3 class="accordion-header">
        <button>Is it easy to learn Javascript?</button>
    </h3>
    <div class="accordion-content">
        <p>Of course, it is easy to learn Javascript.</p>
        <p>It is just that, you have to spend a lot of time with Javascript to become a master of it.</p>
    </div>
</div>

Type the above code inside the <body> tag.

If you notice, the markup is pretty simple.

There is a parent container with the class name accordion and it is wrapping up the accordion header and its associative content.

The accordion header

The accordion header is <button> wrapped inside an h3 tag.

<h3 class="accordion-header">
    <button>Is it easy to learn Javascript?</button>
</h3>

Most people will not use a button for the accordion header.

<!-- This is bad -->
<h3 class="accordion-header">
    Is it easy to learn Javascript?
</h3>

But it is bad for accessibility.

Ideally, A "click" event listener must be added to a button to improve accessibility.

So, I have wrapped the accordion's header text inside a <button>.

The Accordion's content

The markup for the Accordion's content is simple too.

<div class="accordion-content">
    <p>Of course, it is easy to learn Javascript.</p>
    <p>It is just that, you have to spend a lot of time with Javascript to become a master of it.</p>
</div>

It is wrapped up inside a parent container called accordion-content.

Having a parent container for the accordion's content will help us hide or reveal it easily.

The initial preview

Look's bad, isn't it?

Come on, let's fix it.

Let's add some decent CSS

Open up the style.css file and add the following CSS:

.accordion {
    max-width:800px;
    margin:0 auto;
    background-color: #E7F8FF;
    border-radius: 4px;
    box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.1);
    margin-bottom: 30px;
}

/* Accordion header styles */
.accordion-header {
    margin-top: 0;
    margin-bottom: 0;
}
.accordion-header button {
    background-color: transparent;
    border: 0;
    padding: 20px 60px 20px 30px;
    width: 100%;
    cursor: pointer;
    text-align: left;
    position: relative;
    font-weight: bold;
    display:block;
    font-size:18px;
}
.accordion-header button::after {
    content:"";
    border: solid currentcolor;
    border-width: 0 2px 2px 0;
    height: 0.5rem;
    pointer-events: none;
    position: absolute;
    right: 2em;
    top: 50%;
    transform: translateY(-60%) rotate(45deg);
    width: 0.5rem;
}

/* Accordion content styles */
.accordion-content{
    padding: 0 30px 30px;
}
.accordion-content p{
    line-height: 1.44;
}
.accordion-content p:last-child{
    margin-bottom:0;
}

Again, this CSS is nothing fancy.

We are styling the toggle container, its button, and the content.

The only interesting thing in the above CSS is adding an arrow icon to the button via ::after pseudo-element:

.accordion-header button::after {
    content:"";
    border: solid currentcolor;
    border-width: 0 2px 2px 0;
    height: 0.5rem;
    pointer-events: none;
    position: absolute;
    right: 2em;
    top: 50%;
    transform: translateY(-60%) rotate(45deg);
    width: 0.5rem;
}

Here is how the upgraded design looks:

Not bad, right? :D

Let's hide the accordion's content initially

For the initial state, I don't want the accordion's content to be visible.

So, let's just hide it using CSS.

There is a CSS selector called .accordion-content inside the style.css file:

.accordion-content{
    padding: 0 30px 30px;
}

Let's just add new style rules to it.

.accordion-content{
    padding: 0 30px 30px;
    
    /* Hide the content but make it accessible */
    visibility: hidden;
    position: absolute;
    left: -9999px;
}

If you notice, I am not using display:none for hiding the content.

Using display:none will hurt the accessibility of the accordion's content.

It will make the content hidden from the screen readers.

So, instead, I am just visually hiding the content using visibility hidden.

It will not make the content hidden from the screen readers.

But making an element's visibility:hidden will still make the element occupy the visible space on the screen:

So, I am pushing the accordion's content off the screen by using position:absolute and left:-9999px and here is the final output:

Neat, right?

Now, in order to reveal the content of the accordion, all we have to do is change its styles to:

visibility:visible; 
position: static;

And we will learn how to achieve this in the next lesson.