How to Make an Accordion FAQ with JS - part 3

Photo by Kanashi on Unsplash

How to Make an Accordion FAQ with JS - part 3

Adding JavaScript to rotate a button when it's clicked

In the final step of building our accordion FAQ, we'll add styling to our FAQ project and make it a little easier on the eyes. We'll also have the double chevron to rotate to indicate the direction of movement. Currently, our SCSS looks like this:

.answer {
    display: none;
}
.clicked {
    .answer {
        display: block;
  }
}

It's pretty boring, so let's get to work!

SCSS

Inside our body we're going to have our main that will have a class of container. I set the width to 80vw as I like to set an element's size based on the view's screen size versus a hard number in pixels. The margins are set to auto to keep the container centered save for the top, it's 50px, so the container is dropped down from the top of the screen a bit. Here's the code I ended up with:

.container {
    width: 80vw;
    border-radius: 5px;
    padding: 15px;
    margin: 50px auto auto auto;
}

As I mentioned in part 1, the questions themselves are articles, and will be given a class of q, and the articles will contain a div .title, h2 that's the question, our button, a second div with .answer and it will hold a p with the answer to the question.

To keep the code DRY I put some default styles on div like so:

div {
    display: flex;
    margin-left: auto;
    margin-right: auto;
    justify-content: center;
    align-items: center;
}

.q has aborder-radius of 5px to soften the corners, and I added a box-shadow to give it some depth. To keep my code cleaner I used a variable to add shadows (just one of the great things about Sass/SCSS!); in this instance it's $boxshadow: 0 14px 12px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);, so my .q looks like:

.q {
    width: 100%;
    background-color: lavender;
    color: $purple; //variable for #732091
    border-radius: 5px;
    padding-top: 3px;
    margin: 5px 5px 17px 5px; //bottom margin is larger to accomodate the box-shadow
    font-size: 25px;
    font-weight: 600;
    box-shadow: $boxshadow;
}

Inside .q I nested the h2 that will be used to hold the question. Notice the margin set to auto to keep the button to the right.

h2 {
   padding: 7px;
   font-size: 23px;
   margin: auto;
}

The buttons are next, I gave them a margin-right of 10px to nudge them in a little and transition: transform .5s ease-in-out to soften the transitions between movements. Here's the final result:

button {
    cursor: pointer;
    background-color: rgba(255,255,255,0); //removes the background color
    border: 0px;
    padding: 1px 7px;
    color: $purple;
    font-size: 25px;
    font-weight: 600;
    margin-right: 10px;
    text-align: center;
    transition: transform .5s ease-in-out; 
}

I gave my buttons all .qb (for question button) so I could grab them with the JavaScript to add the rotation.

Nested in button I have img, which is what holds the double chevron. The image I used is larger than what I need, so I set the height and let the width figure itself out:

img {
    height: 25px;
    width: auto;
 }

You may not need to do this, it'll depend on the image you select.

Now let's move on to .answer. The most important thing to have is what we set up in part 1: display: none so the answers aren't visible. Everything else is just preferences.

.answer {
    display: none;
    padding: 13px;
    background-color: lavender;
    font-weight: 300;
    font-size: 18px;
    border-radius: 5px;
}

Last is a class that will be added or removed via onClick that will turn the chevron.

.rotate {
    transform: rotate(180deg);
}

Our SCSS is looking pretty good! Now it's time to finish up the JavaScript.

JavsScriptmobile

We need to get access to the chevrons to turn them: we need to add const arrow=quest.querySelector('.qb'); to our JavaScript inside forEach. Next, we'll jump a few lines down into addEventListener where we can toggle the rotate class we just made on arrow like so: arrow.classList.toggle('rotate');. We're using toggle because it's perfect in this situation: if the .rotate isn't present, it's added, otherwise it's removed. Let's take a look at our project:

FAQ-js.gif

If you've made it this far, congrats! You made an accessible accordion FAQ using HTML, SCSS and JavaScript!

Here's the complete code used in this three part tutorial:

HTML

<main class="container">
    <h1>Frequently Asked Questions</h1>
    <article class="q" aria-expanded="false">
        <div class="title">
            <h2>What's the difference between a hippo and a zippo?</h2>
            <button class="qb" aria-label="toggle answer">
                <img src="https://i.ibb.co/KKmX2q3/chevron.png" alt="chevron" />
            </button>
        </div>
        <div class="answer">
            <p>One is really heavy, the other is a little lighter.</p>
        </div>
    </article>
</main>

SCSS

$boxshadow: 0 14px 12px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
$purple: #732091;

.container {
    width: 80vw;
    border-radius: 5px;
    padding: 15px;
    margin: 50px auto auto auto;
}
div {
    display: flex;
    margin-left: auto;
    margin-right: auto;
    justify-content: center;
    align-items: center;
}
.answer {
    display: none;
}
.clicked {
    .answer {
        display: block;
    }
}
.q {
    width: 100%;
    background-color: lavender;
    color: $purple;
    border-radius: 5px;
    padding-top: 3px;
    margin: 5px 5px 17px 5px;
    font-size: 25px;
    font-weight: 600;
    box-shadow: $boxshadow;
    .title {
        width: 100%;
    }
    h2 {
        padding: 7px;
        font-size: 23px;
        margin: auto;
    }
}
button {
    cursor: pointer;
    background-color: rgba(255, 255, 255, 0);
    border: 0px;
    padding: 1px 7px;
    color: $purple;
    font-size: 25px;
    font-weight: 600;
    margin-right: 10px;
    text-align: center;
    transition: transform .5s ease-in-out;
    img {
        height: 25px;
        width: auto;
    }
}
.answer {
    display: none;
    padding: 13px;
    background-color: lavender;
    font-weight: 300;
    font-size: 18px;
    border-radius: 5px;
}
.rotate {
    transform: rotate(180deg);
}

JavaScript

const question=document.querySelectorAll('.q');

question.forEach(function (quest) {
  const btn=quest.querySelector('button');
  let arrow=quest.querySelector('.qb');

  btn.addEventListener('click', function() {

    quest.classList.toggle('clicked');
    arrow.classList.toggle('rotate');

    let ariaValue=quest.getAttribute('aria-expanded');
    ariaValue = (ariaValue === 'false' ? quest.setAttribute('aria-expanded', 'true') : quest.setAttribute('aria-expanded', 'false');
  });

});

I added a few more styles to my finished project, feel free to adjust the styles to your taste. If you've made your own accordion FAQ, please leave a link in the comments! Let me know if you have any questions.

Did you find this article valuable?

Support AC Hulslander by becoming a sponsor. Any amount is appreciated!