I’m trying to create an accordion component, the angle-up element is meant to close the section when you click it but it’s not adding the hide class, what’s the problem?
The html (icons are from font-awesome)
<div class="accordion-items">
<div class="accordion-item">
<p class="item-header">
Lorem ipsum dolor sit amet consectetur.
<i class="angle-down fa fa-angle-down"></i>
<i class="fa fa-angle-up angle-up hide"></i>
</p>
<p class="item-content hide">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor
quos eum cupiditate nulla quas ea numquam praesentium, molestias
culpa nemo ab fuga deserunt.
</p>
<!-- <hr /> -->
</div>
<div class="accordion-item">
<p class="item-header">
Lorem ipsum dolor sit amet consectetur.
<i class="angle-down fa fa-angle-down"></i>
<i class="fa fa-angle-up angle-up hide"></i>
</p>
<p class="item-content hide">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor
quos eum cupiditate nulla quas ea numquam praesentium, molestias
culpa nemo ab fuga deserunt.
</p>
<!-- <hr /> -->
</div>
<div class="accordion-item">
<p class="item-header">
Lorem ipsum dolor sit amet consectetur.
<i class="angle-down fa fa-angle-down"></i>
<i class="fa fa-angle-up angle-up hide"></i>
</p>
<p class="item-content hide">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor
quos eum cupiditate nulla quas ea numquam praesentium, molestias
culpa nemo ab fuga deserunt.
</p>
<!-- <hr /> -->
</div>
<div class="accordion-item">
<p class="item-header">
Lorem ipsum dolor sit amet consectetur.
<i class="angle-down fa fa-angle-down"></i>
<i class="fa fa-angle-up angle-up hide"></i>
</p>
<p class="item-content hide">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor
quos eum cupiditate nulla quas ea numquam praesentium, molestias
culpa nemo ab fuga deserunt.
</p>
<!-- <hr /> -->
</div>
<div class="accordion-item">
<p class="item-header">
Lorem ipsum dolor sit amet consectetur.
<i class="fa fa-angle-down angle-down"></i>
<i class="fa fa-angle-up angle-up hide"></i>
</p>
<p class="item-content hide">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Hic quasi
nam dolorem aliquam, placeat, sed dolores provident natus,
voluptate rem vel numquam. Repellendus.
</p>
<!-- <hr /> -->
</div>
</div>
The css
.hide {
display: none;
}
.bold {
font-weight: 700;
}
p {
padding: 0.5em;
}
.accordion-item {
border-bottom: 1px solid gray;
}
Javascript
"use strict"
const itemHeaderEls = document.querySelectorAll(".item-header")
const itemContentEls = document.querySelectorAll(".item-content")
const angleDownEls = document.querySelectorAll(".angle-down")
const angleUpEls = document.querySelectorAll(".angle-up")
const openItemContent = (i) => {
itemHeaderEls[i].classList.add("bold")
itemContentEls[i].classList.remove("hide")
angleUpEls[i].classList.remove("hide")
angleDownEls[i].classList.add("hide")
}
const closeItemContent = (i) => {
itemHeaderEls[i].classList.remove("bold")
itemContentEls[i].classList.add("hide")
angleUpEls[i].classList.add("hide")
angleDownEls[i].classList.remove("hide")
}
itemHeaderEls.forEach((el) => {
el.addEventListener("click", () => {
const itemIndex = Array.from(itemHeaderEls).indexOf(el)
openItemContent(itemIndex)
})
})
angleUpEls.forEach((el) => {
el.addEventListener("click", () => {
const itemIndex = Array.from(angleUpEls).indexOf(el)
closeItemContent(itemIndex)
})
})
angleDownEls.forEach((el) => {
el.addEventListener("click", () => {
const testIndex = Array.from(angleDownEls).indexOf(el)
openItemContent(testIndex)
})
})
When I click the icon i’d like to add the hide class and remove the bold class, why won’t it work?
>Solution :
As per my comment, the issue is because when you click on the .angle-up or .angle-down elements, the click event is bubbling up to the parent and it causes both the close + open function to be fired at the same time.
The trick is simply to use e.stopPropagation() on the click event handlers bound to the child nodes.
See example below:
const itemHeaderEls = document.querySelectorAll(".item-header")
const itemContentEls = document.querySelectorAll(".item-content")
const angleDownEls = document.querySelectorAll(".angle-down")
const angleUpEls = document.querySelectorAll(".angle-up")
const openItemContent = (i) => {
itemHeaderEls[i].classList.add("bold")
itemContentEls[i].classList.remove("hide")
angleUpEls[i].classList.remove("hide")
angleDownEls[i].classList.add("hide")
}
const closeItemContent = (i) => {
itemHeaderEls[i].classList.remove("bold")
itemContentEls[i].classList.add("hide")
angleUpEls[i].classList.add("hide")
angleDownEls[i].classList.remove("hide")
}
itemHeaderEls.forEach((el) => {
el.addEventListener("click", () => {
const itemIndex = Array.from(itemHeaderEls).indexOf(el)
openItemContent(itemIndex)
})
})
angleUpEls.forEach((el) => {
el.addEventListener("click", (e) => {
e.stopPropagation();
const itemIndex = Array.from(angleUpEls).indexOf(el)
closeItemContent(itemIndex)
})
})
angleDownEls.forEach((el) => {
el.addEventListener("click", (e) => {
e.stopPropagation();
const testIndex = Array.from(angleDownEls).indexOf(el)
openItemContent(testIndex)
})
})
.hide {
display: none !important;
}
.bold {
font-weight: 700;
}
p {
padding: 0.5em;
}
.accordion-item {
border-bottom: 1px solid gray;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" rel="stylesheet" />
<div class="accordion-items">
<div class="accordion-item">
<p class="item-header">
Lorem ipsum dolor sit amet consectetur.
<i class="angle-down fa fa-angle-down"></i>
<i class="fa fa-angle-up angle-up hide"></i>
</p>
<p class="item-content hide">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor quos eum cupiditate nulla quas ea numquam praesentium, molestias culpa nemo ab fuga deserunt.
</p>
</div>
<div class="accordion-item">
<p class="item-header">
Lorem ipsum dolor sit amet consectetur.
<i class="angle-down fa fa-angle-down"></i>
<i class="fa fa-angle-up angle-up hide"></i>
</p>
<p class="item-content hide">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor quos eum cupiditate nulla quas ea numquam praesentium, molestias culpa nemo ab fuga deserunt.
</p>
</div>
<div class="accordion-item">
<p class="item-header">
Lorem ipsum dolor sit amet consectetur.
<i class="angle-down fa fa-angle-down"></i>
<i class="fa fa-angle-up angle-up hide"></i>
</p>
<p class="item-content hide">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor quos eum cupiditate nulla quas ea numquam praesentium, molestias culpa nemo ab fuga deserunt.
</p>
</div>
<div class="accordion-item">
<p class="item-header">
Lorem ipsum dolor sit amet consectetur.
<i class="angle-down fa fa-angle-down"></i>
<i class="fa fa-angle-up angle-up hide"></i>
</p>
<p class="item-content hide">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor quos eum cupiditate nulla quas ea numquam praesentium, molestias culpa nemo ab fuga deserunt.
</p>
</div>
<div class="accordion-item">
<p class="item-header">
Lorem ipsum dolor sit amet consectetur.
<i class="fa fa-angle-down angle-down"></i>
<i class="fa fa-angle-up angle-up hide"></i>
</p>
<p class="item-content hide">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Hic quasi nam dolorem aliquam, placeat, sed dolores provident natus, voluptate rem vel numquam. Repellendus.
</p>
</div>
</div>