For a while now, I've been leaning on Alpine's x-bind:class (or :class for short) syntax to render conditional classes to my <body> element.
I'm usually evaluating a flag found in $store.global and rendering whatever class I want given a condition. No complaints really--It's worked out decently until my latest project.
I could have carried on with this method except that my markup for my opening <body> tag was beginning to get pretty ugly, and my x-bind expression even uglier. My idea was to clean things up by getting these global flags and corresponding classes out of my markup and into my global store, so that's what I did.
TL;DR
I found out by mere playing around, that the x-bind:class expression will take an array of class strings. Easy peasy.
I can even make my expression two characters shorter by using a Alpine getter property in my store, because the property will update anytime one of its dependent variables change.
Let's initialize our store, define a flag to watch, and finally create our getter function that we'll use as our expression for x-bind:class:
<script>
document.addEventListener('alpine:init', () => {
Alpine.store("global", {
on: false,
get bodyClasses() {
let classes = [];
if (this.on) {
classes.push("something-is-on");
}
return classes || "";
}
});
})
</script>
There is most probably a more eloquent and/or more terse code for our getter's code block, but I like what I have here.
Over in our markup, we need to first apply x-data to our body to define it as an Alpine component (I still think this is a misnomer and have commented on this elsewhere) and then add :class="$store.global.bodyClasses":
Now, whenever $store.global.on gets flipped, so will our related body class.
A nice part of bringing this logic out of the markup, is we can uglify the hell out of our class conditionals and not have to muck our up <body> tag...too much.
Neat eh??
Check out the CodePen.
See a way to make this better? Let me know in the comments!
Thanks for reading and code on web assassins!