I have a simple question but it's driving me mad to work out. I'm using AlpineJS to show and hide content. Normally with alpine, the button and content will be in the same element, but here I have it outside of it. This works. But I cannot add classes to both the button and content div when the content is open or closed.
Can anyone guide me please.
<!-- button -->
<div class="mt-4" x-data="{id: 1}">
<button
@click="$dispatch('open-dropdown',{id})"
type="button"
class="bg-white hover:bg-gray-50"
:class="{ 'bg-green-400': open, 'bg-gray-200': !(open) }">
I'm the button
</button>
</div>
<!-- popup 1 -->
<div x-data="{ open: false }"
x-show="open"
@open-dropdown.window="if ($event.detail.id == 1) open = true"
@click.away="open = false">
<div
class="bg-white hover:bg-gray-50"
:class="{ 'bg-green-400': open, 'bg-gray-200': !(open) }">
I'm the content
</div>
</div>
For this you can move the open state inside the global Alpine.js' $store object that is accessible for all component on the page.
<!-- button -->
<div class="mt-4" x-data="{id: 1}">
<button @click="$dispatch('open-dropdown',{id})"
type="button"
class="bg-white hover:bg-gray-50"
:class="{ 'bg-green-400': $store.open, 'bg-gray-200': !($store.open) }">
I'm the button
</button>
</div>
<!-- popup 1 -->
<div x-data
x-show="$store.open"
@open-dropdown.window="if ($event.detail.id == 1) $store.open = true"
@click.away="$store.open = false">
<div class="bg-white hover:bg-gray-50"
:class="{ 'bg-green-400': $store.open, 'bg-gray-200': !($store.open) }">
I'm the content
</div>
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('open', false)
})
</script>
Since our open state in the store is a simple value, we can just replace every open with $store.open. Note that the popup 1 component still requires an empty x-data attribute.