I suspect the issue is with the line const active = document.querySelector(".accordion.active");
in JS code below. It doesn’t seem to be retrieving that element. Could you please help me debug it? Or should I use something else instead of querySelector
? It is also found that this.classList.add("active");
is not adding the "active class" to the accordion element when it is clicked.
document.addEventListener("DOMContentLoaded", function(event) {
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
const active = document.querySelector(".accordion.active");
console.log(active);
if (active) {
active.classList.remove('active'); // remove active class from accordions
}
this.classList.add("active"); // add it to this one
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
});
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 1.5rem;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.active,
.accordion:hover {
background-color: #ccc;
}
.panel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
background: red;
}
.active+.panel {
display: block;
}
<div class="row">
<button class="accordion"><div class="question"><?php echo $label; ?></div></button>
<div class="panel">
<p class="answer">
<?php echo $answer; ?>
</p>
</br>
</div>
</div>
<div class="row">
<button class="accordion"><div class="question"><?php echo $label; ?></div></button>
<div class="panel">
<p class="answer">
<?php echo $answer; ?>
</p>
</br>
</div>
</div>
5
Answers
You don’t need to manipulate the
display
of the active element, your CSS already does that. Also you should not both add and toggle the active class onthis
– that is equivalent to removing it.I’ve also added an if statement to check if the clicked element is already active so that collapsing it again works.
I always prefer delegation.
I am wrapping the accordion in a DIV and delegate the clicks from there
No need to show / hide the panes since the CSS
.active+.panel { display: block; }
does that for us//
this.classList.add("active"); is not adding the "active class" to the accordion element when it is clicked.
//
It is adding. But immediately the class is toggled, so it is removed. That toogle class line is commented.
I have added the css for green color to active accordion, which you can see after moving the cursor off the accordion element.
The below answer is not related to the question, but it is good to have the html hierarchy.
You probably should re-think your approach since in your case, you will not even be in need of JavaScript – for the basics! If you need a custom accordion, then you can use JavaScript, and I try to explain to you how.
What you need is a clean HTML with
<details>
and<summary>
. See this example:With CSS you can style it the way you want it. If you want to remove the arrows, you can try it with
details > summary { list-style: none; }
. Also, you can use any other characters. In this example, we use the signs + (plus) and when the accordion is already opened, it should be – (minus.):As you can see, all open questions remain open. If you want only the active question to stay open, you may use JavaScript.