I've been trying to make a dropdown button that it disactivates when clicking outside of it but I have not find good solution that has good performance, I am making the website with the Astro Framework
so this is an example of what I want it to be like: example
and this is what I have:my website
this is my code:
<nav
class="hidden items-center lg:relative lg:mt-0 lg:!flex lg:basis-auto"
>
<!-- Desktop Navigation -->
<ul
class="list-style-none mr-auto flex flex-col pl-0 lg:flex-row"
>
{navData.map(data => {
if(data.dropdown === true) {
return (
<li data-title={data.title} class="sm:block relative dropdowns mx-2 lg:flex ">
<button data-title={data.title} class="dropdown text-sm rounded flex gap-1 items-center">
{data.title}
<svg viewBox="0 0 1024 1024" class="icon w-3" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"><path d="M903.232 256l56.768 50.432L512 768 64 306.432 120.768 256 512 659.072z" ></path></g></svg>
</button>
<div data-title={data.title} class="absolute right-0 top-7 mt-2 w-48 bg-gray-800 rounded-md overflow-hidden z-10 hidden">
{data.subcat.map(el => (
<a href={el.slug} class="block px-4 py-2 text-sm text-gray-200 hover:bg-gray-700">
{el.title}
</a>
))}
</div>
</li>
)}
else {
return (
<li class="mb-4 pl-2 lg:mb-0 lg:pl-0 lg:pr-1" data-te-nav-item-ref>
<a
class="p-0 text-sm transition duration-200 hover:ease-in-out motion-reduce:transition-none lg:px-2"
href={`${data.slug}`}
data-te-nav-link-ref
>
{data.title}
</a>
</li>
)
}
})}
</ul>
</nav>
const dropdownToggle = document.querySelectorAll('.dropdown');
const dropdownMenu = document.querySelectorAll('.dropdowns > div');
dropdownToggle.forEach(button => button.addEventListener('click', () => {
dropdownMenu.forEach((el) => {
if(button.getAttribute('data-title') === el.getAttribute('data-title')){
el.classList.toggle('hidden')
}
});
}))
I've tried to use focus-within but didn't work as expected
.dropdowns:focus-within > div {
display: block;
}
and I think this solution:
window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
is bad for performance