I am having some difficulty using using an accordion in HTML & JS. I am trying to code it so only one accordion is open at a time. If someone clicks and opens a new accordion, all the other should close. This my HTML.
<div >
<div >
<div >
HUMBER RADIO
</div>
<div >
<div >
<ul>
<li><a href="">RADIO NEWS</a></li>
<li><a href="">PODCAST</a></li>
<li><a href="">CONTENT</a></li>
</ul>
</div>
</div>
</div>
</div>
<div >
<div >
<div >
TV NEWS
</div>
<div >
<div >
<ul>
<li><a href="">COVID UPDATES</a></li>
<li><a href="">NORTH CAMPUS NEWS</a></li>
<li><a href="">LAKESHORE CAMPUS NEWS</a></li>
</ul>
</div>
</div>
</div>
</div>
Here is the JavaScript for the code. It can open all of them, but I am struggling to program it so the others close.
window.onload = pageReady;
function pageReady() {
const accordionItemHeaders = document.querySelectorAll(".accordion-item-header");
accordionItemHeaders.forEach(accordionItemHeader => {
accordionItemHeader.addEventListener("click", event => {
accordionItemHeader.classList.toggle("active");
const accordionItemBody = accordionItemHeader.nextElementSibling;
if(accordionItemHeader.classList.contains("active")) {
accordionItemBody.style.maxHeight = "100px";
}
else {
accordionItemBody.style.maxHeight = "0px";
}
});
});
}
CodePudding user response:
A couple of tweaks:
Before setting the currently clicked header to
.active
, we select the previously active header (if it exists) and remove that class.Instead of setting inline styles using JavaScript, here's the cleaner alternative of setting
max-height
using just CSS, with the adjacent sibling combinator (a plus sign) to select the accordion body that follows the active accordion header.
const accordionItemHeaders = document.querySelectorAll(".accordion-item-header");
accordionItemHeaders.forEach(accordionItemHeader => {
accordionItemHeader.addEventListener("click", event => {
if (event.target.classList.contains('active')) {
accordionItemHeader.classList.remove("active");
} else {
document.querySelector(".accordion-item-header.active")?.classList.remove("active");
accordionItemHeader.classList.add("active");
}
});
});
.accordion-item-header.active .accordion-item-body {
max-height: 100px;
}
CodePudding user response:
Similar to Jon's excellent answer we are going to let CSS handle the styling and just use javascript to manipulate classes.
The main difference is we are going to accommodate multiple accordion groups and utilize event bubbling. The event listener will be attached to the accordion group and then check the event target. This is also handy if you end up injecting more elements into the accordions with JS.
//Get the Accordion Groups
const accordions = document.querySelectorAll(".accordion");
accordions.forEach(accordion => {
//Add event listener to each ACCORDION , use function not fat arrow to get access to "this"
accordion.addEventListener("click", function(event) {
//Check the event targe is an item header
if (event.target.matches(".accordion-item-header")) {
//Get current active, here "this" refers to the accordion group clicked on
let active = this.querySelector(".active");
//Toggle element if active element clicked
if (active == event.target) {
event.target.classList.toggle("active");
} else {
//Remove current active.
if (active) {
active.classList.remove("active");
}
//Add active
event.target.classList.add("active");
}
}
});
});
.accordion {
width: 45%;
display: inline-block;
vertical-align: top;
}
.accordion .accordion-item-header .accordion-item-body {
max-height: 0px;
overflow: hidden;
transition: all 0.5s;
}
.accordion .accordion-item-header.active .accordion-item-body {
max-height: 100px;
}
<div >
<h2>Accordion Group 1</h2>
<div >
<div >
HUMBER RADIO
</div>
<div >
<div >
<ul>
<li><a href="">RADIO NEWS</a></li>
<li><a href="">PODCAST</a></li>
<li><a href="">CONTENT</a></li>
</ul>
</div>
</div>
</div>
<div >
<div >
TV NEWS
</div>
<div >
<div >
<ul>
<li><a href="">COVID UPDATES</a></li>
<li><a href="">NORTH CAMPUS NEWS</a></li>
<li><a href="">LAKESHORE CAMPUS NEWS</a></li>
</ul>
</div>
</div>
</div>
</div>
<div >
<h2>Accordion Group 1</h2>
<div >
<div >
JJJ RADIO
</div>
<div >
<div >
<ul>
<li><a href="">RADIO NEWS</a></li>
<li><a href="">PODCAST</a></li>
<li><a href="">CONTENT</a></li>
</ul>
</div>
</div>
</div>
<div >
<div >
Radio NEWS
</div>
<div >
<div >
<ul>
<li><a href="">COVID UPDATES</a></li>
<li><a href="">NORTH CAMPUS NEWS</a></li>
<li><a href="">LAKESHORE CAMPUS NEWS</a></li>
</ul>
</div>
</div>
</div>
</div>
CodePudding user response:
You don't need to stress yourself, just the bootstrap HTML JavaScript user interface library, you can Google search about it, they have every UI component you can use