I am using Tailwind CSS for styling my site, and adding Alpine as progressive enhancement to certain elements (e.g. navigation). As a result, I would like the ability to remove and add classes to some elements when Alpine initialises, as some of my "non-js" styles are not required.
Is it possible to remove classes from elements on Alpine initialisation? Currently I am doing this to add classes, in this example it is to make the header fixed when javascript and Alpine are running:
x-data="{ navOpen: false }"
:class="[navOpen ? 'fixed' : 'fixed']"
But I would also like to remove some classes as well.
Any pointers would be great
Good question. I've not actually needed to do this, will do some research. Maybe @HugoDF or @SimoTod will know an answer sooner, or @calebporzio if he's not busy rewriting Alpine ;)
From working on this part of the codebase, there isn't a mechanism for it.
When the class attribute is bound the classes from :class will be added to the static classes from class.
So to support this should probably only use the classes in the binding.
It's possible you could return a callback from the x-init directive if you want to run some code after Alpine has initialised and run it's first DOM updates.
You could remove / add the class then. You'll have access to the initial component data here too.
As the guys said, it's not possible at the moment. You can either use init as suggested by Ryan or you can write your css in a way that, when Alpine classes are added, other classes stop working. I think you can add something like 'alpine-loaded' and use the not selector in your css .yourclasss:not(.alpine-loaded) {...rules that you want to apply only without alpine...}
Hi all,
Thanks for all the responses, I appreciate it.
@SimoTod this would definitely work - I am aiming not to write custom CSS for this project beyond Tailwind customisations, but will do this if I can't get an "on-page" solution to work
@ryangjchandler I am trying the x-init approach you suggest, as that method seems to provide what I am after. Is it possible to run this on elements within the component? Reduced test case component below to illustrate what I am attempting:
<div
x-data="{ open: false }"
>
<button
class="hidden"
x-init="() => { $el.classList.remove('hidden');$el.classList.add('block') }"
>
Button</button>
</div>
I am new to Alpine so may be mis-using the $el or x-init properties here, but the above does not work for me. If I add the x-init to the same element as x-data it functions as I would expect.
Thanks again for the help, really enjoying using Alpine
x-init can only be used on the root element, similar to how Vue's mounted hook is at the component level too.
Basically you can have something like
<div x-data="{...}" x-init="$refs.mybutton.classList.remove('hidden')">
<button :class="block" x-ref="mybutton">click me</button>
</div>
I've typed it from my phone so there could be typos in the snippet but that's the general concept. You can check out the x-ref section in the readme for more details.
If you are just after hiding elements before Alpine starts, you probably just want to use x-cloak (https://github.com/alpinejs/alpine/blob/master/README.md#x-cloak). You'll just need to add 1 line of css in that case.
That is great! Between x-cloak and the $refs method from @SimoTod above I have the toolkit I need to do my progressive enhancement of components.
Thanks for the help all
You can try something like
:class="{ 'block' : !open , 'hidden' : open}"
or
:class="{ 'block' : open , 'hidden' : !open}"
depend on what you need, in this case the class will be removed and add a new class
Most helpful comment
Basically you can have something like
I've typed it from my phone so there could be typos in the snippet but that's the general concept. You can check out the x-ref section in the readme for more details.
If you are just after hiding elements before Alpine starts, you probably just want to use x-cloak (https://github.com/alpinejs/alpine/blob/master/README.md#x-cloak). You'll just need to add 1 line of css in that case.