I've been looking around here for an example drop down nav menu that does three things:
- When the user CLICK on the menu drop it shows the drop down (this works)
- When the user CLICKS outside of the nav area or anywhere else on the page is closes an open drops (this works too)
- When a user CLICKS on another drop down if one is already open, it closes the previously open drop and opens the new drop menu. <-(I'm stuck here).
Currently if you click on one drop menu, then click on another, the first stays open. I want any other menus that are open to close if you click on another drop down. But i want to retain the behavior that when the user clicks outside of the menu anywhere in the document it closes too.
I've found several SO posts that solve some of this. However sometimes they nav bar only has 1 drop down as an example. Other times for some reason the solution causes other issues in my nav. So i decided to create a new post.
Please note that i'm learning JS and jquery now.
Here is my code:
$(document).ready(function() {
$('.dropdown').click(function(e) {
e.stopPropagation();
// hide all dropdown that may be visible -
// this works but it breaks the functionality of toggling open and closed
// when you click on the menu item
e.preventDefault();
// close when click outside
$(this).find('.dropdown-content').toggleClass('open')
});
// Close dropdown when u click outside of the nav ul
$(document).click(function(e) {
if (!e.target.closest("ul") && $(".dropdown-content").hasClass("open")) {
$(".dropdown-content").removeClass("open");
}
})
});
.nav__topbar {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
min-height: 2em;
background: #fff;
}
.nav__links {
overflow: hidden;
display: flex;
align-items: center;
margin-left: auto!important;
a {
float: left;
display: block;
text-align: center;
padding: 14px 16px;
text-decoration: none;
&:hover {
color: #ccc;
}
}
.icon {
display: none;
}
}
.nav__links .dropdown .dropdown-content {
position: absolute;
max-width: 25%;
}
.dropdown .dropbtn,
.nav__links a {
font-size: 1.5em!important;
color: #222;
}
/* Upon click the menu should turn into a vertical stacked menu with a soft drop shadow */
.nav__links.vertical {
position: absolute;
display: flex;
flex-direction: column;
align-items: flex-start;
padding-top: 2em;
top: 50%;
left: 70%;
background-color: #fff;
z-index: 1;
border: 1px solid #f2f3f3;
border-radius: 4px;
background: #fff;
-webkit-box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
}
.dropdown {
float: left;
overflow: hidden;
}
/* Codepen doesn't like when i nest styles */
.dropdown .dropbtn {
border: none;
outline: none;
padding: 14px 16px;
background-color: inherit;
font-family: inherit;
margin: 0;
}
.dropdown {
cursor: pointer;
display: block;
&:hover {
background-color: #444;
}
}
/* Style the dropdown content (hidden by default) */
.dropdown-content {
display: none;
background-color: #fff;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
width: 100%;
transition: all 0.25s ease-in;
transform: translateY(-10px);
}
/* Style the links inside the dropdown codepen doesn't like my nesting */
.dropdown-content a {
float: none;
text-decoration: none;
display: block;
text-align: left;
}
.dropdown-content li,
.nav__links li,
.nav__links li a {
list-style-type: none;
text-decoration: none;
}
.dropdown li {
padding: 20px
}
.dropdown .dropdown-content.open {
display: block;
padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<nav >
<ul >
<li data-hover="title">
<button >community <span >▼</span>
</button>
<ul >
<li><a href="#" >item 1</a></li>
<li><a href="#" >item 2</a></li>
<li><a href="#" >item 3</a></li>
</ul>
</li>
<li><a href="#">Menu item 2</a></li>
<li data-hover="title">
<button >menu <span >▼</span>
</button>
<ul >
<li><a href="#" >item 1</a></li>
<li><a href="#" >item 2</a></li>
<li><a href="#" >item 3</a></li>
</ul>
</li>
<li data-hover="title">
<button >menu <span >▼</span>
</button>
<ul >
<li><a href="#" >item 1</a></li>
<li><a href="#" >item 2</a></li>
<li><a href="#" >item 3</a></li>
</ul>
</li>
</ul>
</nav>
And here [is a codepen](https://codepen.io/lwasser/pen/BaVKYNX as well with the same code in case you want to play with the code.
UPDATE: the code above works with the fixes provided in the accepted answer below! The code had another bug which was drop down links didn't work. but i was able to remove / fix that by removing:
e.stopPropagation();
e.preventDefault();
Many thanks for the folks who helped below!! And i'll try to fully update my codepen with the hamburger as well as soon as I can in case that helps people.
CodePudding user response:
You are almost there!
Store in a var the clicked element.
Remove the
open
class name from all elements except the clicked one.Toggle
theopen
class of the clicked element.$(document).ready(function () { $(".dropdown").click(function (e) { e.stopPropagation(); e.preventDefault(); // 1. Store in a var the clicked element var current_dropdown = $(this).find(".dropdown-content"); $(".dropdown-content").each(function() { var element = $(this); // 2. Remove the `open` class name from all elements except the clicked one. if (!element.is(current_dropdown)) { $(this).removeClass("open"); } }); // 3. Toggle the open class of the clicked element. current_dropdown.toggleClass("open"); }); // Close dropdown when u click outside of the nav ul $(document).click(function (e) { if (!e.target.closest("ul") && $(".dropdown-content").hasClass("open")) { $(".dropdown-content").removeClass("open"); } }); });
I forked your codepen:
https://codepen.io/Valeriu-Ciuca/pen/KKezYME
CodePudding user response:
While adding the open class, remove open class of the other dropdowns
$(this).siblings('.dropdown').find('.dropdown-content').removeClass('open');
Finding the siblings with dropdown class and removing open class of the corresponding element.
$(document).ready(function () {
$(".dropdown").click(function (e) {
e.stopPropagation();
e.preventDefault();
// close when click outside
$(this).find(".dropdown-content").toggleClass("open");
$(this).siblings('.dropdown').find('.dropdown-content').removeClass('open');
});
// Close dropdown when u click outside of the nav ul
$(document).click(function (e) {
if (!e.target.closest("ul") && $(".dropdown-content").hasClass("open")) {
$(".dropdown-content").removeClass("open");
}
});
});
.nav__topbar {
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
min-height: 2em;
background: #fff;
}
.nav__links {
overflow: hidden;
display: flex;
align-items: center;
margin-left: auto!important;
a {
float: left;
display: block;
text-align: center;
padding: 14px 16px;
text-decoration: none;
&:hover {
color: #ccc;
}
}
.icon {
display: none;
}
}
.dropdown .dropbtn, .nav__links a {
font-size: 1.5em!important;
color: #222;
}
/* Upon click the menu should turn into a vertical stacked menu with a soft drop shadow */
.nav__links.vertical {
position: absolute;
display: flex;
flex-direction: column;
align-items: flex-start;
padding-top: 2em;
top: 50%;
left: 70%;
background-color: #fff;
z-index: 1;
border: 1px solid #f2f3f3;
border-radius: 4px;
background: #fff;
-webkit-box-shadow: 0 2px 4px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12);
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12);
}
.dropdown {
float: left;
overflow: hidden;
}
/* Codepen doesn't like when i nest styles */
.dropdown .dropbtn {
border: none;
outline: none;
padding: 14px 16px;
background-color: inherit;
font-family: inherit;
margin: 0;
}
.dropdown {
cursor: pointer;
display: block;
&:hover {
background-color: #444;
}
}
/* Style the dropdown content (hidden by default) */
.dropdown-content {
display: none;
background-color: #fff;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
width: 100%;
transition: all 0.25s ease-in;
transform: translateY(-10px);
}
/* Style the links inside the dropdown codepen doesn't like my nesting */
.dropdown-content a {
float: none;
text-decoration: none;
display: block;
text-align: left;
}
.dropdown-content li, .nav__links li, .nav__links li a {
list-style-type: none;
text-decoration: none;
}
.dropdown li {
padding: 20px
}
.dropdown .dropdown-content.open {
display: block;
padding: 0;
}
.nav__links .dropdown .dropdown-content {
position: absolute;
max-width: 25%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><html>
<head>
</head>
<body>
<nav >
<ul >
<li data-hover="title">
<button >community <span >▼</span>
</button>
<ul >
<li><a href="#">item 1</a></li>
<li><a href="#">item 2</a></li>
<li><a href="#">item 3</a></li>
</ul>
</li>
<li><a href="#">Menu item 2</a></li>
<li data-hover="title">
<button >menu <span >▼</span>
</button>
<ul >
<li><a href="#">item 1</a></li>
<li><a href="#">item 2</a></li>
<li><a href="#">item 3</a></li>
</ul>
</li>
<li data-hover="title">
<button >menu <span >▼</span>
</button>
<ul >
<li><a href="#">item 1</a></li>
<li><a href="#">item 2</a></li>
<li><a href="#">item 3</a></li>
</ul>
</li>
</ul>
</nav>
</body>
</html>