Class toggling to implement the accordion functionality

Class toggling to implement the accordion functionality

In the last lesson, we set up the foundations for implementing the accordion functionality.

And here is the progress we have made so far:

But when we click on the Accordion header, nothing happens.

We want to open or close the accordion when its header is clicked.

To achieve it, first, we need to add an event listener to the accordion header.

So open up the index.js file and type the following code:

//Select the accordion header
const accordionHeader = document.querySelector(".accordion .accordion-header");

//Add event listener and handler to it
accordionHeader.addEventListener("click", toggleAccordionContent);

//Defined a function for toggling the accordion content
function toggleAccordionContent(){
    console.log("Accordion header is clicked");
}

In the above code, we are selecting the accordion header and adding a "click" event listener to it.

We have also defined a function toggleAccordionContent and we are using it as the event handler for the "click" events on the accordion header.

So, whenever the accordion header is clicked, the toggleAccordionContent function will be called and the code inside it will get executed.

Finally, when the accordion header is clicked, we are just logging a message to the console:

0:00
/0:04

Simple. Nothing new.

Opening and closing the accordion

Next, when the accordion header is clicked for the first time, we need to open the accordion by making its content visible.

And when the accordion header is clicked again, we need to close the accordion by hiding its content.

There are several ways to achieve this.

But the simplest way is by adding or removing a class name, like is_open, to the accordion.

How does it work?

1) The initial state

If you remember, currently the accordion is closed because we are hiding the accordion content by making its visibility:hidden:

<div class="accordion">
    <h3 class="accordion-header">
        <!-- ... -->
    </h3>
    <div class="accordion-content">
        <!-- ... -->
    </div>
</div>
.accordion-content{
    padding: 0 30px 30px;
    
    /* Hide the content but make it accessible */
    visibility: hidden;
    position: absolute;
    left: -9999px;
}

2) Adding the "is_open" class to open the accordion

Now the idea is, We need to add the is_open class to the .accordion element to open it up and make its content visible.

<div class="accordion is_open">
    <h3 class="accordion-header">
        <!-- ... -->
    </h3>
    <div class="accordion-content">
        <!-- ... -->
    </div>
</div>

Adding the class is_open is not enough to make the accordion open.

This technique relies on CSS to open up the accordion.

In other words, we need to write the supporting CSS rule:

.accordion.is_open .accordion-content {
    visibility: visible;
    position: static;
}

The above CSS rule will make the accordion content visible if the is_open class is present on its parent container .accordion.

So, add the above CSS to the end of the CSS file.

3) Remove the "is_open" class to close the accordion

If we remove the is_open class, the accordion will be closed again by hiding its content.

This is because the following CSS rule that makes the content visible is no longer applicable:

.accordion.is_open .accordion-content {
    visibility: visible;
    position: static;
}

So, the accordion will revert back to its closed state.

The test

If you now go ahead and add the is_open class manually to the .accordion element, the accordion is opening up by making its content visible.

And when you remove it, the accordion is getting closed.

0:00
/0:04

But we don't want to do this manually, right?

We want to open or close the accordion only when the accordion header is clicked.

So, here is our end goal:

  1. When the accordion header is clicked for the first time, we should add the is_open class to the .accordion. This will open up the accordion by revealing its content.
  2. When the accordion header is clicked again, we should remove the is_open class from the .accordion. This will close down the accordion by hiding its content.

And to achieve our end goal, we need to use the classList.toggle method to add or remove the is_open class.

How to use it?

Update your code inside the toggleAccordionContent function to use the classList.toggle method.

const accordionHeader = document.querySelector(".accordion .accordion-header");

accordionHeader.addEventListener("click", toggleAccordionContent);

function toggleAccordionContent(){
    //Select the accordion
    const accordion = document.querySelector(".accordion");
    
    //And add the class when the header is clicked
    accordion.classList.toggle("is_open");
}

What's happening?

1) Initially, When we load the index.html in the browser, there is no is_open class present on the .accordion element.

So, the content is hidden.

2) Then when we click on the accordion header for the first time:

  1. The classList.toggle method checks whether the is_open class is present on the .accordion element.
  2. And because the class is not present, it will get added the .accordion element.

This results in the accordion getting opened by making its content visible.

0:00
/0:04

3) And when we click on the accordion header again:

  1. Again, the classList.toggle method checks whether the is_open class is present on the .accordion element.
  2. And because it is currently present, the class will be removed.

This results in the accordion getting closed by hiding its content.

0:00
/0:04

That's all.

This is exactly how the class toggling and javascript work together.

And the same technique can be used when we are performing any kind of toggle functionality.

For example, the same technique can be used for implementing the off-canvas menu component.

We will do this in an upcoming lesson really fast.

But before that...

Let's enhance our accordion styling when it is open

Now I want to quickly shift your focus to the arrow icon that is part of the accordion header.

When the accordion is closed, the arrow is pointing down.

But when the accordion is open, it is still pointing down.

We should make it point upward when the accordion is open, right?

To achieve this, add the following CSS to the end of the style.css file:

.accordion.is_open .accordion-header button::after {
    transform: translateY(-50%) rotate(-135deg);
}

The is_open class being present on the accordion is an indication that the accordion is open.

So, we are taking advantage of it and wrote a CSS rule that rotates the icon upwards if the accordion is open.

And this results in:

Now, I have a small task to test your knowledge

If the accordion is open, I want you to change the background color of the accordion to light yellow.

Come on, go ahead and do it.

...

Solution

.accordion.is_open {
    background-color: #fcfbf3;
}

And this results in:

0:00
/0:03