Close FAQ accordion when same question is clicked - javascript

I have created an Accordion with HTML/JS. Everything works fine but when I click a Question, It expands the panel but when I click the same question again It doesn't close.
I have created this script using W3Schools tutorial- https://www.w3schools.com/howto/howto_js_accordion.asp
Here is my code -
var acc = document.getElementsByClassName("accordion1");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
for (j = 0; j < acc.length; j++) {
acc[j].nextElementSibling.style.maxHeight = null;
}
this.classList.toggle("accordion1:active");
var panel = this.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
.accordion1 {
background-color: #fff;
color: #444;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 14px;
transition: .4s
}
.accordion1:active,
.accordion1:hover {
background-color: #5d4b79;
color: #fff
}
.accordion1:after {
content: '\002B';
color: #fff;
font-weight: 700;
float: right;
margin-left: 5px
}
.accordion1:active:after {
content: "\2212"
}
.panel1 {
padding: 0 18px;
background-color: #fff;
max-height: 0;
overflow: hidden;
transition: max-height .2s ease-out
}
<button class="accordion1">Question 1</button>
<div class="panel1">
<p>Answer 1</p>
</div>
<button class="accordion1">Question 2</button>
<div class="panel1">
<p>Answer 2</p>
</div>
<button class="accordion1">Question 3</button>
<div class="panel1">
<p>Answer 3</p>
</div>
Any help appreciated.

You need to change some code. Jonah Walker Already Resolved this problem.
Here's Codepen Link
He has already commented on his code. Hopefully, your problem will be solved.
var acc = document.getElementsByClassName("accordion");
var i;
// Open the first accordion
var firstAccordion = acc[0];
var firstPanel = firstAccordion.nextElementSibling;
firstAccordion.classList.add("active");
firstPanel.style.maxHeight = firstPanel.scrollHeight + "px";
// Add onclick listener to every accordion element
for (i = 0; i < acc.length; i++) {
acc[i].onclick = function() {
// For toggling purposes detect if the clicked section is already "active"
var isActive = this.classList.contains("active");
// Close all accordions
var allAccordions = document.getElementsByClassName("accordion");
for (j = 0; j < allAccordions.length; j++) {
// Remove active class from section header
allAccordions[j].classList.remove("active");
// Remove the max-height class from the panel to close it
var panel = allAccordions[j].nextElementSibling;
var maxHeightValue = getStyle(panel, "maxHeight");
if (maxHeightValue !== "0px") {
panel.style.maxHeight = null;
}
}
// Toggle the clicked section using a ternary operator
isActive ? this.classList.remove("active") : this.classList.add("active");
// Toggle the panel element
var panel = this.nextElementSibling;
var maxHeightValue = getStyle(panel, "maxHeight");
if (maxHeightValue !== "0px") {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
};
}
// Cross-browser way to get the computed height of a certain element. Credit to #CMS on StackOverflow (http://stackoverflow.com/a/2531934/7926565)
function getStyle(el, styleProp) {
var value, defaultView = (el.ownerDocument || document).defaultView;
// W3C standard way:
if (defaultView && defaultView.getComputedStyle) {
// sanitize property name to css notation
// (hypen separated words eg. font-Size)
styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
} else if (el.currentStyle) { // IE
// sanitize property name to camelCase
styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
return letter.toUpperCase();
});
value = el.currentStyle[styleProp];
// convert other units to pixels on IE
if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
return (function(value) {
var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
el.runtimeStyle.left = el.currentStyle.left;
el.style.left = value || 0;
value = el.style.pixelLeft + "px";
el.style.left = oldLeft;
el.runtimeStyle.left = oldRsLeft;
return value;
})(value);
}
return value;
}
}
button.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
button.accordion.active, button.accordion:hover {
background-color: #ddd;
}
button.accordion:after {
content: '\002B';
color: #777;
font-weight: bold;
float: right;
margin-left: 5px;
}
button.accordion.active:after {
content: "\2212";
}
div.panel {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
<button class="accordion">Question 1</button>
<div class="panel">
<p>Answer 1</p>
</div>
<button class="accordion">Question 2</button>
<div class="panel">
<p>Answer 2</p>
</div>
<button class="accordion">Question 3</button>
<div class="panel">
<p>Answer 3</p>
</div>

I suggest you use a class to set the max-height, since you already have max-height: 0 for class .panel1, you can add another class that sets max-height: none for when the panel is displayed.
var acc = document.getElementsByClassName("accordion1");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
for (j = 0; j < acc.length; j++) {
acc[j].nextElementSibling.classList.remove("panelactive");
}
this.classList.toggle("accordion1:active");
var panel = this.nextElementSibling;
panel.classList.toggle("panelactive");
});
}
.accordion1 {
background-color: #fff;
color: #444;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 14px;
transition: .4s
}
.accordion1:active,
.accordion1:hover {
background-color: #5d4b79;
color: #fff
}
.accordion1:after {
content: '\002B';
color: #fff;
font-weight: 700;
float: right;
margin-left: 5px
}
.accordion1:active:after {
content: "\2212"
}
.panel1 {
padding: 0 18px;
background-color: #fff;
max-height: 0;
overflow: hidden;
transition: max-height .2s ease-out
}
.panelactive {
max-height: none;
}
<button class="accordion1">Question 1</button>
<div class="panel1">
<p>Answer 1</p>
</div>
<button class="accordion1">Question 2</button>
<div class="panel1">
<p>Answer 2</p>
</div>
<button class="accordion1">Question 3</button>
<div class="panel1">
<p>Answer 3</p>
</div>

Related

How To Reset Button Back To Original State After Clicking On It Again?

I have an accordion where the panels are pseudo buttons that expand the accordion content once the "buttons" are clicked and the currently open accordion panel closes once I click on another one. The problem I have is that if I click on the panel once to open the accordion and click on it again to close it, it stays focused (the orange border remains) and I cannot figure out how to bring the button back to the state it was in before I clicked it? In the same way it is reset when I click on another panel?
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
var panel = this.nextElementSibling;
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
let active = document.querySelectorAll(".accordion-div .accordion.active");
for (let j = 0; j < active.length; j++) {
active[j].classList.remove("active");
active[j].nextElementSibling.style.maxHeight = null;
}
this.classList.toggle("active");
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
.accordion {
color: #fff;
background-color: #00000042;
cursor: pointer;
padding: 10px 10px;
margin-top: 20px;
width: 100%;
border: 1px solid #00000042;
text-align: left;
outline: none;
transition: 0.4s;
}
.active,
.accordion:hover {
background-color: #00000042;
border: 1px solid #fc8e2d;
}
.panel {
padding: 0 18px;
font-size: 18px;
background-color: #00000042;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
<div class="accordion-div">
<button class="accordion"><span class="faq__question-heading">Title1</span></button>
<div class="panel">
<p style="padding:18px 0;">description1</p>
</div>
<button class="accordion"><span class="faq__question-heading">Title2</span></button>
<div class="panel">
<p style="padding:18px 0;">description2</p>
</div>
<button class="accordion"><span class="faq__question-heading">Title3</span></button>
<div class="panel">
<p style="padding:18px 0;">description3</p>
</div>
</div>
Can anyone help me how I should change my code?
I tried changing the JavaScript by using this
for (var j = 0; j < acc.length; j++) {
acc[j].nextElementSibling.style.maxHeight = null;
}
but it messes up the entire JS and it stops working.
Change your code to this:
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
var panel = this.nextElementSibling;
if (panel.style.maxHeight){
panel.style.maxHeight = null;
} else {
let active = document.querySelectorAll(".accordion-div .accordion.active");
for(let j = 0; j < active.length; j++){
active[j].classList.remove("active");
active[j].nextElementSibling.style.maxHeight = null;
}
// this.classList.toggle("active"); // move this down, outside of
// both if and else, since it should apply in any case
panel.style.maxHeight = panel.scrollHeight + "px";
}
this.classList.toggle("active"); // just add this
});
}
.accordion {
color: #fff;
background-color: #00000042;
cursor: pointer;
padding: 10px 10px;
margin-top:20px;
width: 100%;
border: 1px solid #00000042;
text-align: left;
outline: none;
transition: 0.4s;
}
.active, .accordion:hover {
background-color: #00000042;
border: 1px solid #fc8e2d;
}
.panel {
padding: 0 18px;
font-size: 18px;
background-color: #00000042;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
<div class="accordion-div">
<button class="accordion"><span class="faq__question-heading">Title1</span></button>
<div class="panel">
<p style="padding:18px 0;">description1</p>
</div>
<button class="accordion"><span class="faq__question-heading">Title2</span></button>
<div class="panel">
<p style="padding:18px 0;">description2</p>
</div>
<button class="accordion"><span class="faq__question-heading">Title3</span></button>
<div class="panel">
<p style="padding:18px 0;">description3</p>
</div>
</div>
The reason for the change - toggling of the active class should happen regardless of whether the clicked element had that class or not.
Also, as an aside - instead of having a click event handler for every panel (addEventListener within a loop), consider using delegation - attach the event handler on the parent element, and check if the receiver of the click was your panel.
For example:
var acc = document.querySelector(".accordion-div");
acc.addEventListener("click", function(e) {
var target = e.target;
if(!target.classList.contains("accordion")) {
return false;
}
var panel = target.nextElementSibling;
if (panel.style.maxHeight){
panel.style.maxHeight = null;
} else {
let active = document.querySelectorAll(".accordion-div .accordion.active");
for(let j = 0; j < active.length; j++){
active[j].classList.remove("active");
active[j].nextElementSibling.style.maxHeight = null;
}
panel.style.maxHeight = panel.scrollHeight + "px";
}
target.classList.toggle("active");
});
.accordion {
color: #fff;
background-color: #00000042;
cursor: pointer;
padding: 10px 10px;
margin-top:20px;
width: 100%;
border: 1px solid #00000042;
text-align: left;
outline: none;
transition: 0.4s;
}
.active, .accordion:hover {
background-color: #00000042;
border: 1px solid #fc8e2d;
}
.panel {
padding: 0 18px;
font-size: 18px;
background-color: #00000042;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
<div class="accordion-div">
<button class="accordion"><span class="faq__question-heading">Title1</span></button>
<div class="panel">
<p style="padding:18px 0;">description1</p>
</div>
<button class="accordion"><span class="faq__question-heading">Title2</span></button>
<div class="panel">
<p style="padding:18px 0;">description2</p>
</div>
<button class="accordion"><span class="faq__question-heading">Title3</span></button>
<div class="panel">
<p style="padding:18px 0;">description3</p>
</div>
</div>

Animated Collapsibles

I found this nice future to collapse elements on w3schools: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_collapsible_symbol
I would like to revert it, so that all elements are shown when page is loaded, and then use this future to toggle between visible/hidden..
I have this code:
<style>
.collapsible {
background-color: #777;
color: white;
cursor: pointer;
padding: 5px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 12px;
}
.collapsible:after {
content: '\002B';
color: white;
font-weight: bold;
float: right;
margin-left: 5px;
}
.collapsible.active:after {
content: "\2212";
}
.content {
padding: 0 20px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
</style>
<script>
$(document).ready(function() {
var coll = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = this.nextElementSibling;
if (content.style.maxHeight){
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
});
</script>
Example here: https://jsfiddle.net/g50v4cL2/
So when page is loaded, i want to have it like this:
And then able to collapse.. can anyone help me with this?
Thank you.
There're many ways to do it, in this case, I tried to not make many changes and to stick to the way you have, so you can just add active class to your elements, and change your js code a bit to be like this:
var coll = document.getElementsByClassName("collapsible");
var i;
const adjustContentHeight = (content) => {
if (content.style.maxHeight){
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
}
for (i = 0; i < coll.length; i++) {
adjustContentHeight(coll[i].nextElementSibling);
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
adjustContentHeight(this.nextElementSibling);
});
}
.collapsible {
background-color: #777;
color: white;
cursor: pointer;
padding: 5px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 12px;
}
.collapsible:after {
content: '\002B';
color: white;
font-weight: bold;
float: right;
margin-left: 5px;
}
.collapsible.active:after {
content: "\2212";
}
.content {
padding: 0 20px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
<button class='collapsible active'>Test1</button>
<div class='content'>
<label><input type = 'checkbox' value = 'value1'/> value1</label>
<label><input type = 'checkbox' value = 'value2'/> value2</label>
<label><input type = 'checkbox' value = 'value3'/> value3</label>
<label><input type = 'checkbox' value = 'value4'/> value4</label>
</div>
<button class='collapsible active'>Test2</button>
<div class='content'>
<label><input type = 'checkbox' value = 'value5'/> value5</label>
<label><input type = 'checkbox' value = 'value6'/> value6</label>
<label><input type = 'checkbox' value = 'value7'/> value7</label>
</div>
If you don't want to see this transition in the beginning, consider removing the transition property from css and adding it in js after this code

Javascript not opening/closing accordion

I've tried a few different ways but can not tell why my.JS isn't opening and closing my accordion. Please check my code. Your help would be appreciated.
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
/*this javascript seems to be fine and matches what some answers have said, and i've reset the page cache but i cannot seem to get it to work */
body {
text-align: center;
background-color: #ffffff;
}
h1 {
font: 40px courier new;
text-align: center;
}
a {
font: 25px arial;
text-align:center;
}
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 60%;
text-align: center;
border: none;
outline: none;
transition: 0.4s;
}
.active, .accordion:hover {
background-color: #ccc;
}
.panel {
padding: 0 18px;
background-color: white;
overflow: hidden;
font: 16px Source Sans Pro;
width:60%;
margin:0 auto;
display:none;
height:200px auto
}
p{
text-align:center;
}
<div class="wrap1">
<button class="accordion">About Us Page Map</button>
<div id="pan1" class="panel">
<p>
Personel section<br />
Acheivments<br />
History<br />
</p>
</div>
</div>
I've added the css, i do have a class called accordion but it didn't show in the original question sorry!
The problem is here:
var acc = document.getElementsByClassName("accordion");
You don't have "accordion" class in your HTML file, that's why it is not able to recognize it. You have to take a button, assign it a class named accordion and then it will work properly.
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
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: 18px;
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;
}
<button class="accordion">Personal</button>
<div class="panel">
<p>Personal here</p>
</div>
<button class="accordion">Achievements</button>
<div class="panel">
<p>Achievements here</p>
</div>
<button class="accordion">History</button>
<div class="panel">
<p>History here</p>
</div>
Source: HTML and CSS Accordion - w3schools
Hope this helps.
I would suggest refactoring some of your code to make it more readable such as
HTML
Item 1
<div id="item1" class="accordion-content">This is my accordion Item 1 content</div>
Item 2
<div id="item2" class="accordion-content">This is my accordion Item 2 content</div>
JS
document.querySelectorAll(".accordion").forEach(function(node) {
node.addEventListener("click", function(e) {
this.nextElementSibling.toggleClass("active');
});
});
CSS
.accordion-content:not(.active) {
display: none;
}
Besides the refactor, I'm unable to see an element with the className accordion. It seems you are missing the HTML containing the actual accordion.

Accordion stoped working after i pasted it in my

i have site running on wordpress template.
i've pasted in the whole accordion code from W3School (here it is https://www.w3schools.com/howto/howto_js_accordion.asp).
my version unexpectedly doesn't work.
i've included css lines in the main.css file:
....
/* styles for accordion*/
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
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;
background-color: white;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
/*end styles for accordion*/
i've added the html code on the page through the admin console:
<h2>Accordion</h2>
<button class="accordion">Section 1</button>
<div class="panel"> <p>Lorem ipsum</p> </div>
<button class="accordion">Section 2</button>
<div class="panel"> <p>Lorem ipsum</p> </div>
<button class="accordion">Section 3</button>
<div class="panel"> <p>Lorem ipsum</p> </div>
next i've created scripts.js file and added it into the template with wp_enqueue_script in functions.php. so i can see it loads when the page code is shown.
content of the scripts.js file:
$(document).ready(function() {
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
}
});
then nothing happens on click on the accordion: no js errors in the console, no content of the accordion shows up. how could i make it work?
upd 1
changed class names to unique ones
js
var acc = document.getElementsByClassName("nikaccordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("nikactive");
var nikpanel = this.nextElementSibling;
if (nikpanel.style.display === "block") {
nikpanel.style.display = "none";
} else {
nikpanel.style.display = "block";
}
});
}
css:
/* styles for accordion*/
.nikaccordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
.nikactive, .nikaccordion:hover {
background-color: #ccc;
}
.nikpanel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
}
/*end styles for accordion*/
html:
<h2>Accordion</h2>
<button class="nikaccordion">Section 1</button>
<div class="nikpanel">
<p>Lorem ipsum</p>
</div>
<button class="nikaccordion">Section 2</button>
<div class="nikpanel">
<p>Lorem ipsum </p>
</div>
<button class="nikaccordion">Section 3</button>
<div class="nikpanel">
<p>Lorem ipsum </p>
</div>
upd 2
when im changing the order of the .js files that my file goes at the end of a list then i get an error
Uncaught TypeError: Cannot read property 'style' of null
at HTMLButtonElement.<anonymous> (scripts.js?ver=5.2.2:8)
so i suppose the
var nikpanel = this.nextElementSibling;
doesn't work
Your mistake is that you've mixed the basic version (non-animated) with the animated one.
For the basic version remove the min-height:0; and replace it with display:none.
This is because your max-height is 0 and your javascript code is changing the display value from 'none' to 'block' and vice-versa on click. Therefore, the element becomes a block element, however, it's height is limited by max-height:0.
Your CSS should be:
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
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;
background-color: white;
display: none;
overflow: hidden;
}
Or you could just change your JS to change the max-height value instead of the display value.
var acc = document.getElementsByClassName("accordion");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.maxHeight){
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = panel.scrollHeight + "px";
}
});
}
In your CSS replace
.panel {
padding: 0 18px;
background-color: white;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
with
.panel {
padding: 0 18px;
display: none;
background-color: white;
overflow: hidden;
}
I've just tested your code and just that replacement get it working
i found out that WordPress adds p-tags to my html code thus the js script treated the phantom p-tags as target tags and tried to apply actions to them.
i disabled this addings by:
remove_filter( 'the_content', 'wpautop' );
remove_filter( 'the_excerpt', 'wpautop' );
in my functions.php

removing a class when a search box is clicked

TLDR; The functionality I'm trying to create in this code example is upon clicking a box (collapsible has active class), and then you click on the search box, the active class is removed closing the collapsible. Currently, the remove class is not working. Any idea why?
In more detail:
I have a list of collapsible blocks get an active class when they are clicked. You can search a search box to filter out which block you want to be displayed, and thus click on it to display more content. I have realized that when you go back to search and didn't 'unclick' a box (to close the collapsible) the box is still active (which makes perfect sense).
I had an idea that upon search box focus, I would loop through all the collapsible and remove the active class itself (in turn, closing the collapsible).
I've gotten to the point where I can find which collapsible is active, but I cannot remove the active class.
Is this because the box was initially clicked to add the class and has to be physically clicked once again to remove it?
var coll = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = this.nextElementSibling;
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
function searchClick() {
var searchTable;
searchTable = document.getElementById("search-table");
faqButtons = searchTable.getElementsByTagName("button");
for (i = 0; i < faqButtons.length; i++) {
if (faqButtons[i].classList.contains("active")) {
console.log('THIS ONE: ', faqButtons[i]);
faqButtons[i].classList.remove("active");
}
}
}
.collapsible {
display: flex;
justify-content: space-between;
background-color: white;
color: black;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 20px;
}
.collapsible span {
padding-left: 5px;
padding-right: 5px;
}
.collapsible .active,
.collapsible:hover {
background-color: #333;
color: white;
}
.content {
padding: 0 18px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
.content p {
margin-top: 10px;
}
<div class="search-faq">
<input autocomplete="off" type="text" id="search-faq" placeholder="Search for FAQ" onfocus="searchClick()" />
</div>
<div id="search-table" class="superHidden">
<div id="wolfandgrizzly-FAQ-search">
<h1>A to B sales</h1>
<button class="collapsible"><span>What are our shipping policies?</span></button>
<div class="content">
<p>
They are crazy cool.
</p>
</div>
<button class="collapsible"><span>Are you making more products?</span></button>
<div class="content">
<p>
We'll sell you more very soon
</p>
</div>
</div>
I don't see where you are getting that the active class is not being removed. It doesn't appear that there is a problem with that. I think the problem is that you are showing the answers via maxHeight setting, but you aren't resetting it when you click the search box. I've updated it in this snippet, but essentially it boiled down to adding the following in your loop:
var content = faqButtons[i].nextElementSibling
content.style.maxHeight = null
var coll = document.getElementsByClassName("collapsible");
var i;
for (i = 0; i < coll.length; i++) {
coll[i].addEventListener("click", function() {
this.classList.toggle("active");
var content = this.nextElementSibling;
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
function searchClick() {
var searchTable;
searchTable = document.getElementById("search-table");
faqButtons = searchTable.getElementsByTagName("button");
for (i = 0; i < faqButtons.length; i++) {
if (faqButtons[i].classList.contains("active")) {
console.log('THIS ONE: ', faqButtons[i]);
faqButtons[i].classList.remove("active");
}
var content = faqButtons[i].nextElementSibling
content.style.maxHeight = null
}
}
.collapsible {
display: flex;
justify-content: space-between;
background-color: white;
color: black;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 20px;
}
.collapsible span {
padding-left: 5px;
padding-right: 5px;
}
.collapsible .active,
.collapsible:hover {
background-color: #333;
color: white;
}
.content {
padding: 0 18px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
}
.content p {
margin-top: 10px;
}
<div class="search-faq">
<input autocomplete="off" type="text" id="search-faq" placeholder="Search for FAQ" onfocus="searchClick()" />
</div>
<div id="search-table" class="superHidden">
<div id="wolfandgrizzly-FAQ-search">
<h1>A to B sales</h1>
<button class="collapsible"><span>What are our shipping policies?</span></button>
<div class="content">
<p>
They are crazy cool.
</p>
</div>
<button class="collapsible"><span>Are you making more products?</span></button>
<div class="content">
<p>
We'll sell you more very soon
</p>
</div>
</div>
Here's an approach that uses as little JavaScript as possible. If JavaScript is disabled, the only thing that will break is the search box. Sections will still open and close as expected when clicked.
The accordion stores its state in checkboxes, one in each section. Each section's title is a label element which toggles that section's checkbox when clicked. The sections are expanded and collapsed using CSS :checked selectors.
var sections = [].slice.call(document.querySelectorAll(".accordion li")),
searchAccordion = function() {
var value = document.getElementById("search").value.toLowerCase();
sections.map(function(section) {
var content = section.textContent.toLowerCase();
section.querySelector("input").checked = content.includes(value);
});
};
body {
font-family: sans-serif;
}
.accordion {
padding-left: 0;
margin: -1rem;
}
.accordion li {
list-style-type: none;
}
.accordion input {
display: none;
}
.accordion label {
background-color: #eee;
transition: background-color 100ms;
cursor: pointer;
font-size: 1.2rem;
padding: 1rem;
display: block;
}
.accordion label:hover {
background-color: #444;
color: white;
}
.accordion .content {
padding: 1rem;
display: none;
}
.accordion input:checked ~ .content {
display: block;
}
<input id="search" onKeyup="searchAccordion()" type="text" placeholder="Search for FAQ" autocomplete="off">
<h1>A to B sales</h1>
<ul class="accordion">
<li>
<input type="checkbox" id="section1">
<label for="section1">What are our shipping policies?</label>
<div class="content">They are crazy cool.</div>
</li>
<li>
<input type="checkbox" id="section2">
<label for="section2">Are you making more products?</label>
<div class="content">We'll sell you more very soon</div>
</li>
</ul>

Categories

Resources