I'm using Alpine JS as part of a TALL project. I have a navigation menu here, which, for the purposes of this Stackoverflow I've condensed heavily to the barebones. Only one dropdown can be open at any one time, and within a dropdown there would be links to other menu items. All is good.
The part I'm struggling with, is I want all dropdowns to close when clicking away from the current dropdown, you know, away from the div that's open. I still want to be able to toggle a dropdown via the button. But not sure how to achieve the result from within an open dropdown.
Here's my markup
<nav x-data="{ openDropdown: null }">
<div class="mx-auto h-20 max-w-7xl px-2 sm:px-6 lg:px-8">
<ul>
<li x-data="{ id: 'products' }">
<button x-on:click="openDropdown = openDropdown === id ? null : id" type="button" class="inline-block text-white hover:text-secondary-200 px-3 py-2 text-base font-medium">
Products
</button>
<template x-if="openDropdown === id">
<div>
...
</div>
</template>
</li>
<li>
<a href="/" class="inline-block text-white hover:text-secondary-200 px-3 py-2 text-base font-medium">
Integrations
</a>
</li>
<li x-data="{ id: 'features' }">
<button x-on:click="openDropdown = openDropdown === id ? null : id" type="button" class="inline-block text-white hover:text-secondary-200 px-3 py-2 text-base font-medium">
Features
</button>
<template x-if="openDropdown === id">
<div>
...
</div>
</template>
</li>
</ul>
</div>
</nav>
A simple solution is to use the click.outside event applied to the <ul> element:
<ul @click.outside="openDropdown = null">
<li x-data="{ id: 'products' }">
.....
but if you want to close the current dropdown also when you click on the elements without a dropdown, you must reset the openDropdown variable also when clicking on them (unless they open a different page):
<li @click="openDropdown=null">
<a href="/" class=".....">
Integrations
</a>
</li>
Instead of x-if you could use a x-show directive applied to the element to show/hide:
<li x-data="{ id: 'products' }">
<button @click="openDropdown = openDropdown === id ? null : id"
type="button"
class="....."
>
Products
</button>
<div x-show="openDropdown === id">
.....
</div>