The dropdown menu should open when the button is clicked.
And if you click outside the dropdown it should close again.
I tried this by adding an event listener to the body when the dropdown menu is active and then checking if the click happened outside the dropdown.
How can I write the following code without timeout function and make the dropdown close when clicked outside and not inside?
<div >
Open Dropdown
<div >
<a >Link Text</a>
<a >Link Text</a>
<a >Link Text</a>
<a >Link Text</a>
</div>
</div>
.dropdown {
position: relative;
cursor: pointer;
user-select: none;
&__window {
position: absolute;
background: $background-alt;
width: 100%;
max-width: 260px;
top: 45px;
z-index: 12;
overflow: hidden;
display: none;
visibility: hidden;
&--active {
display: block;
visibility: visible;
}
> * {
width: 100%;
display: block;
color: $white;
white-space: nowrap;
&:hover {
background: $background;
color: currentColor;
}
}
}
}
let dropdownBtn = document.querySelectorAll('.dropdown__open')
dropdownBtn.forEach((el) => {
let dropdownWindow = el.querySelector('.dropdown__window')
el.addEventListener('click', function () {
dropdownWindow.classList.toggle('dropdown__window--active')
window.setTimeout(function () {
if (dropdownWindow.classList.contains('dropdown__window--active')) {
let clickListener = document.body.addEventListener(
'click',
function (event) {
if (event.target.classList != 'dropdown__link') {
dropdownWindow.classList.remove('dropdown__window--active')
// Buggy clickListener.removeEventListener()
}
}
)
}
}, 1000)
})
})
OR https://codepen.io/Salala2/pen/RwxjOzW
CodePudding user response:
You can use the window.onclick
. And if you don't want your dropdown to close when each of the dropdown items is clicked, you can specify that as a condition too.
const dropDownButton = document.querySelector('.dropdown__open')
const dropDownWindow = document.querySelector('.dropdown__window')
dropDownButton.addEventListener('click',
()=> dropDownWindow.classList.toggle('dropdown__window--active'))
window.onclick = function(e){
if (!e.target.matches('.dropdown__open') &&
dropDownWindow.classList.contains('dropdown__window--active')){
dropDownWindow.classList.remove('dropdown__window--active')
}
}
CodePudding user response:
You can use onBlur()
. But in order to do that you need to add tabindex="0"
to the invoking element i.e the element which is invoking dropdown to display.
const dropdown = document.querySelector('.dropdown');
const dropdownWindow = document.querySelector('.dropdown__window')
dropdown.addEventListener('click', (event) => {
dropdownWindow.classList.toggle('dropdown__window--active');
});
dropdown.addEventListener('blur', (event) => {
dropdownWindow.classList.remove('dropdown__window--active');
});
.dropdown {
position: relative;
cursor: pointer;
user-select: none;
max-width: 260px;
}
.dropdown__window {
position: absolute;
background: #ccc;
box-shadow: 0 10px 40px #1d2021;
width: 100%;
max-width: 260px;
top: 45px;
z-index: 12;
overflow: hidden;
display: none;
visibility: hidden;
}
.dropdown__window--active {
display: block;
visibility: visible;
}
.dropdown__window>* {
font-size: 14px;
cursor: pointer;
display: block;
padding: 1rem 0 1rem 1rem;
font-weight: 400;
text-align: left;
line-height: 1.42857143;
color: #fff;
white-space: nowrap;
}
<div tabindex="0">
Open Dropdown
<div >
<a >Link Text</a>
<a >Link Text</a>
<a >Link Text</a>
<a >Link Text</a>
</div>
</div>
CodePudding user response:
//Dropdowns
let dropdownBtn = document.querySelectorAll('.dropdown__open')[0]
let dropdownWindow = document.querySelector('.dropdown__window')
dropdownBtn.addEventListener('click', function (event) {
dropdownWindow.classList.toggle('dropdown__window--active')
})
document.addEventListener('click', function(event) {
var isClickInsideElement = dropdownBtn.contains(event.target);
if (!isClickInsideElement) {
dropdownWindow.classList.remove('dropdown__window--active')
}
})
Try out this approach, hope it helps.