I'm using Alpinejs and Tailwind.
I'm trying to create an accordion with a toggle on each tab, but I want that toggle to trigger at the same time as when a user clicks to open each part of the accordion... here's what I got so far:
<ul class="block mb-4" x-data="{pay:null}">
<li class="flex flex-col">
<div @click="pay !== 'cc' ? pay = 'cc' : pay = null" class="cursor-pointer px-5 py-3 flex items-center bg-blue-50 border text-xl font-semibold border-blue-800 text-blue-800 inline-block hover:shadow rounded-t">
<button type="button" class="relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-orange-500 bg-gray-200" x-data="{ on: false }" aria-pressed="false" :aria-pressed="on.toString()" @click="on = !on" x-state:on="Enabled" x-state:off="Not Enabled" :class="{ 'bg-orange-500': on, 'bg-white': !(on) }">
<span class="sr-only">Credit Card</span>
<span aria-hidden="true" class="pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 translate-x-0" x-state:on="Enabled" x-state:off="Not Enabled" :class="{ 'translate-x-5': on, 'translate-x-0': !(on) }"></span>
</button>
<span class="ml-2">Credit / Debit Card</span>
</div>
<p x-show="pay == 'cc'" class="bg-white border-l border-r border-blue-800 py-4 px-2">
This is made with Alpine JS and Tailwind CSS
</p>
</li>
<li class="flex align-center flex-col">
<h4 @click="pay !== 1 ? pay = 1 : pay = null" class="cursor-pointer px-5 py-3 bg-indigo-400 text-white text-center inline-block hover:opacity-75 hover:shadow hover:-mb-3">Accordion item 2</h4>
<p x-show="pay == 1" class="border py-4 px-2">
There's no external CSS or JS
</p>
</li>
<li class="flex align-center flex-col">
<h4 @click="pay !== 2 ? pay = 2 : pay = null" :class="{'cursor-pointer px-5 py-3 bg-indigo-500 text-white text-center inline-block hover:opacity-75 hover:shadow hover:-mb-3': true, 'rounded-b': pay != 2}">Accordion item 3</h4>
<p x-show="pay == 2" :class="{'border py-4 px-2': true, 'rounded-b': pay == 2}">
Pretty cool huh?
</p>
</li>
</ul>
I'm pretty green, so bear with me. I actually just want to comment but don't have enough reputation.
First of all, you need to remove bg-gray-200
from your <button class>
because you're binding :class="{ bg-{color} }
for on: true
and on: false
states. Another one is bg-orange-500
and ring-orange-500
isn't a defined utility on Tailwind CSS. Maybe you mean bg-yellow-500
and ring-yellow-500
? Other than that, what is x-state
? I can't find it in Alpine.js docs.
Okay, about your requested problem, your code actually has 2 issues.
parent
component to communicate with a child
component, like a nested component. Alpine.js doesn't do that. Either you merge both components holding multiple properties in the parent
component so that you only have one x-data
or you $dispatch('customEvent')
on your <div>
at the @click
event (together with pay
toggling) and listen to the @customEvent.window
on your <button>
component. Alternatively, you can install Alpine Magic Helpers for the $component/$parent
communication or install Spruce for saving all states.
<button>
is nested in your <div>
, you're firing both @click
events every time you @click
the <button>
. This is why your code looks like the <button>
component communicates with your <ul>
component which is untrue. You're firing two different @click
events. Because of this behavior, if you $dispatch('customEvent')
from your <div>
component and listen to the @customEvent.window
on your <button>
, you'll end up toggling your on
state twice. Try add @click.debounce.250
on your <button>
together with the @customEvent.window
and you'll see it toggles to and fro. As for that, you need to remove @click
event on your <button>
while listening to the @customEvent.window
so that the toggling happens once, or better you merge both x-data
making your <ul>
holding multiple properties (no need to $dispatch('customEvent')
on your <div>
and @click
on your <button>
, just one @click
on your <div>
).
In my implementation, I make x-data
to hold both:
<ul class="block mb-4" x-data="{pay:null, on: false}">
<li class="flex flex-col">
<div @click="pay !== 'cc' ? pay = 'cc' : pay = null, on = !on" class="cursor-pointer px-5 py-3 flex items-center bg-blue-50 border text-xl font-semibold border-blue-800 text-blue-800 inline-block hover:shadow rounded-t">
<button type="button" class="relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-500" aria-pressed="false" :aria-pressed="on.toString()" x-state:on="Enabled" x-state:off="Not Enabled" :class="{ 'bg-yellow-500': on, 'bg-gray-200': !(on) }">
<span class="sr-only">Credit Card</span>
<span aria-hidden="true" class="pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200 translate-x-0" x-state:on="Enabled" x-state:off="Not Enabled" :class="{ 'translate-x-5': on, 'translate-x-0': !(on) }"></span>
</button>
<span class="ml-2">Credit / Debit Card</span>
</div>
<p x-show="pay == 'cc'" class="bg-white border-l border-r border-blue-800 py-4 px-2">
This is made with Alpine JS and Tailwind CSS
</p>
</li>
<li class="flex align-center flex-col">
<h4 @click="pay !== 1 ? pay = 1 : pay = null" class="cursor-pointer px-5 py-3 bg-indigo-400 text-white text-center inline-block hover:opacity-75 hover:shadow hover:-mb-3">Accordion item 2</h4>
<p x-show="pay == 1" class="border py-4 px-2">
There's no external CSS or JS
</p>
</li>
<li class="flex align-center flex-col">
<h4 @click="pay !== 2 ? pay = 2 : pay = null" :class="{'cursor-pointer px-5 py-3 bg-indigo-500 text-white text-center inline-block hover:opacity-75 hover:shadow hover:-mb-3': true, 'rounded-b': pay != 2}">Accordion item 3</h4>
<p x-show="pay == 2" :class="{'border py-4 px-2': true, 'rounded-b': pay == 2}">
Pretty cool huh?
</p>
</li>
</ul>
Accordions (among other components) are now part of official AlpineJS documentation . Use them for perfect out of the box accordions.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.