Reputation: 470
I've got a list of tabs where if a user clicks on a tab for e.g. "Tab 1" then it'll show the copy that sits under this tab, and if they click on "Tab 2", the copy under this tab will show and the copy under "Tab 1" would close and so on.
This works how i want it to, but what I'm struggling with is if the user clicks on a tab i want them to be able to close the same tab. Any help on this would be appreciated.
document.querySelectorAll('.tabs-menu a').forEach(function(el) {
el.addEventListener('click', function(event) {
event.preventDefault();
this.closest('.tabs-menu')
.querySelector('.current')
.classList.remove("current");
this.closest('a').classList.add("current");
document.querySelectorAll('.tab-content').forEach(function(a) {
a.style.display = "none";
});
var activeTab = this.getAttribute("href");
document.querySelector(activeTab).style.display = "block";
});
});
.tab-content {
display: none;
}
<ul class="tabs-menu">
<li><a href="#tab-1">Tab 1</a></li>
<div id="tab-1" class="current tab-content">tab 1 content</div>
<li><a href="#tab-2">Tab 2</a></li>
<div id="tab-2" class="tab-content">tab 2 content</div>
<li><a href="#tab-3">Tab 3</a></li>
<div id="tab-3" class="tab-content">tab 3 content</div>
<li><a href="#tab-4">Tab 4</a></li>
<div id="tab-4" class="tab-content">tab 4 content</div>
</ul>
Upvotes: 2
Views: 236
Reputation: 470
I took another look at this and created the below which looks to work the way i want it to.
var acc = document.querySelectorAll('.tabs-menu li');
var i;
var open = null;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function() {
if (open == this) {
open.classList.toggle("active");
open = null;
} else {
if (open != null) {
open.classList.toggle("active");
}
this.classList.toggle("active");
open = this;
}
});
}
.tab-content {
display: none;
}
.tabs-menu .active+.tab-content {
display: block;
}
<ul class="tabs-menu">
<li><a href="#tab-1">Tab 1</a></li>
<div id="tab-1" class="tab-content">tab 1 content</div>
<li><a href="#tab-2">Tab 2</a></li>
<div id="tab-2" class="tab-content">tab 2 content</div>
<li><a href="#tab-3">Tab 3</a></li>
<div id="tab-3" class="tab-content">tab 3 content</div>
<li><a href="#tab-4">Tab 4</a></li>
<div id="tab-4" class="tab-content">tab 4 content</div>
</ul>
Upvotes: 1
Reputation: 61055
You're looking for the closest anchor element from an anchor element. I doubt that's what you want. Keep in mind that this always refers to the clicked element, not what you found in the line above.
Then, you just want to introduce a check for the current
class and act accordingly:
document.querySelectorAll('.tabs-menu a').forEach(function(el) {
el.addEventListener('click', function(event) {
event.preventDefault();
// if the tab is already active...
if (this.classList.contains('current')) {
// deactivate all tabs
this.closest('.tabs-menu')
.querySelector('.current')
.classList.remove("current");
// hide all tab panes
document.querySelectorAll('.tab-content').forEach(function(pane) {
pane.style.display = "none";
});
// otherwise...
} else {
// activate this tab
this.classList.add("current");
// hide all tab panes
document.querySelectorAll('.tab-content').forEach(function(pane) {
pane.style.display = "none";
});
// show the tab pane that correlates to this tab
var activeTab = this.getAttribute("href");
document.querySelector(activeTab).style.display = "block";
}
});
});
.tab-content {
display: none;
}
a.current+.tab-content {
display: block;
}
<ul class="tabs-menu">
<li><a href="#tab-1">Tab 1</a></li>
<div id="tab-1" class="tab-content">tab 1 content</div>
<li><a href="#tab-2">Tab 2</a></li>
<div id="tab-2" class="tab-content">tab 2 content</div>
<li><a href="#tab-3">Tab 3</a></li>
<div id="tab-3" class="tab-content">tab 3 content</div>
<li><a href="#tab-4">Tab 4</a></li>
<div id="tab-4" class="tab-content">tab 4 content</div>
</ul>
There's one final issue, and that's that the forEach
loop is asynchronous, so sometimes the pane doesn't show because the call to show it runs ahead of the call to hide all panes. You'll need to implement a promise or other mechanism to deal with that. Read more
Upvotes: 0