Introduction to Alpine.js
What's up guys, Andre here and today I'd like to take a look at Alpine.js. Alpine is a rugged, minimal framework for composing JavaScript behavior in your markup. Think of it like Tailwind for JavaScript.
Now, in my opinion, it's not meant to replace a Vue or React, but serve as an alternative when you need JavaScript to do something minor. For example, you have a server-driven app like Laravel or Rails and all you want to do is toggle the visibility of some components—components like a drop-down menu, a hamburger menu, or tabs. So I have a Laravel app here with a few components that need some JavaScript to toggle the visibility of them. So as you can see, we have a drop-down here, we have some FAQs that are meant to be toggled, and we have some tabs down here.
Now, if this were a Vue app with Vue CLI or a React app with Create React App, then you're already within the context of a JavaScript framework, so you wouldn't need Alpine. However, like I said, this is a Laravel app, so we have a few options to integrate JavaScript. We can install and use Vue, which certainly isn't difficult but does require some steps and might feel a bit overkill if all you're doing is toggling some components. You can use vanilla JS, which doesn't require any external libraries but does take some effort to write it in a declarative way like in Vue. Or we can use Alpine.js, which has a very small footprint and lets us write our JavaScript in a Vue-like declarative way.
Setup and Core Concepts
So let's go ahead and make use of Alpine here. So I am going to install it, and we can either get it from the CDN or use NPM. I'm just gonna use the CDN. So it says add it to the end of your head section, and everything I've written so far is just within the welcome.blade.php in Laravel, and I am making use of Tailwind here. Alpine and Tailwind pair very nicely with each other. So let me add the script. Cool, and that's what we have to do, and we can start using Alpine.
So if you read the documentation here on the GitHub page, you'll see that it's very similar to Vue. So you have a bunch of attributes that you just set in your HTML and you have state using this x-data attribute. You can set your state in here and then the scope of this state is within this element and all of its children. And then you have events similar to Vue, and you can toggle the state on them or even make methods if you want. So yeah, like I said, I think its best use case is for minor UI stuff like toggling the visibility of components.
So let's go ahead and start with this dropdown. Let's grab this, and then we'll put it on our dropdown here. So let's go into our code and look for that dropdown. So this is a button, so this is my avatar and also this chevron down, and then this ul is the actual dropdown. So let's put it on this wrapping div which wraps the button and the dropdown. So it's called x-data—let's say isOpen instead—and it's set to false by default. Okay, and now we want to have a click event and then change the state on the button. So let's do that.
So this would be on the button. The button is right here. Let's go ahead and do that. Change to isOpen, and it sets the state to true. Okay, and now all we have to do is use the x-show attribute here, similar to v-show in Vue. Or we can use x-if as well if you want to do that, but I'm going to stick with x-show because if you use x-if you have to add a template tag and I don't want to do that. So let's just show it when the state isOpen.
And it also has support for clicking away, which is great, so we can click off the dropdown and it will disappear. So let's add this to our dropdown. And that should do it. So I'm gonna add it to my ul here. Let me just indent this. And that's isOpen. Okay. And that's it.
Let's see if our dropdown works. So back here, refresh, and it's not visible... visible. Cool. We can also click off of it, and that works. Cool. And it also has support for modifiers. So again, similar to Vue, if we want to press Escape and have this disappear, then we can do that as well. We just have to go here and set it on the button. We might need it on these ones as well, but I'll just stick to the button up here. So we just have to add @keydown.escape and then just set isOpen to false. Okay, let's try that out. Let's refresh it. Open it up, then press escape, and that works. Cool.
Creating an FAQ Accordion
Okay, now let's take a look at these FAQs and do something similar and just toggle the content here. So for now I have this whole thing as a button, which is fine, but it's a bit ugly with this outline, but that's cool. So let's add—let's go to it first. And if you look at my markup structure, you'll see that I have a wrapping div for each question. So this button is the first element, and then the answer is the second element, and we have a wrapping div here. So let's put it on here—or the state on here. So pretty much the same thing we did for the dropdown. So x-data="{ isOpen: false }". Again, this is the same name as the other one, but it's within a different scope, so that's fine. And let's set the event on the button so @click="isOpen = !isOpen". So just toggling it.
And let's set the visibility using x-show and we just want to check if it's open. Okay, so that should work. There you go, it's false by default. And if you just click anywhere here, it should show and toggle. Awesome.
Now I also have a minus icon here which I want to toggle as well. So let's add the show on that as well. And this is the icon. So I want to see it... there it is. And this is toggled between them so this is the plus icon. So let's show it when it's not isOpen. And unfortunately, at the time of this recording, there's no x-else yet, so we have to use x-show again and just do the opposite, which is fine. So it's isOpen, and now that icon should toggle as well. Cool.
Now you can do the same thing for this, but that might be some repeated code. So you have a few options here. Again, you can repeat it if you want, it's not too much code, or you can change the state of this to make it higher and have both of these in this state. But then we'll need a piece of state to toggle the visibility of each of the questions. Or the third option, which you can't do yet, but I'm guessing will be available, is to use something like a v-for. So right now in Alpine, there's no support for loops yet using x-for, but if that comes, then you should be able to loop over your FAQs and then just add events for each iteration in the loop.
Implementing Dynamic Tabs
Okay, now let's take a look at the tabs and get that to work. So there's an example here if you want to look at that, and we'll be doing something like this. So let's look for where our tabs are, right here. And it's within an unordered list. So let's put the state in here. So I'm gonna do x-data="{ tab: 'tab1' }" and the default would be tab1.
And we have to add click events on each of these anchor tags. Let's go ahead and do that and put them on their own line. Okay, so let's add it right here. So let's say @click.prevent. We can also do a .prevent to prevent the default, just like in Vue, and we just have to set the tab for each one. So tab = 'tab1', and change this one to tab2, and tab3. Okay.
And now for the content, I only have one section here, but we need three for each of the tabs. So let's wrap these in a div and we'll just indent it, and then we'll duplicate it two more times. And then we will add an x-show on each of them. So the first one... let's do it together here. Okay, and so say x-show="tab === 'tab1'", two, and three. tab1 for that one, tab2 for this one, and tab3 for this one. And there's a few other classes we have to hide or show, but let's see if this works first. And let's change the content. So this is Tab 1 Content, Tab 2 Content, and Tab 3 Content. Okay, does that work? Actually, it's not working. It's showing all the content right now.
Okay, so yeah, I have to put my state up higher. So as you saw I put my state within this ul, and this is not a child, it's a sibling. So we have to put this up one. So let's put it within the container, the container of this tab thing. So this right here, that should do it. See if that works. Okay, Tab 1... oh, sorry, looks like I didn't put this in the right place. So this should be obviously within the <a> tag, and I put it in the wrong... I put it in the closing tag. So that's what I get for trying to be fancy with the multiple cursors. So let's change this as well. I think I got the first one right, though. So put it here, and that should do it. I got the first one right. So yeah, this one is within the <a> tag. Okay, so see if this works. There we go. Tab 1, Tab 2, Tab 3. And you can see the content switching here, but we have to change the active state.
Handling Active Tab Styles
So we got to change some of the classes based on which tab is selected. So let's go ahead and do that. So let's look at the active state and see the styles that are applied when we're active. So the background is white, the color is slightly darker blue, and I think that's it. Okay, let's do that. So let's take these out. So bg-white and text-blue-700... change that. Yes, yeah, that looks... oh and also these three borders. And see how that looks. Cool. And now let's set that only when it's active.
So for conditional class rendering, you can do the same thing that you're used to in Vue. So let's do that. So let's just put :class and let's make an object here and let's re-add those classes only when it's active. So it was bg-white, text-blue-700, and the three borders, which I'll paste in. And we want to apply those classes when tab === 'tab1'. And we have to do the same thing for the other ones as well. And I think I have to put a hover:text-blue-800 on this as well. Okay, see if this works. And now the active state should come back here. And it doesn't. ... I forgot to close the bracket. ... And that doesn't work because I forgot a quote here. Let's try it again. And there we go. So now we have to add it to the other ones and that should work. So let me just grab this line and put it to the other ones. Okay, and let's see if this works. Tab 1, Tab 2, Tab 3. And why isn't the highlight working? So yeah, let's remove this bg-gray-100. So that seems to be taking precedence. And now it's working. Cool.
Adding CSS Transitions
Okay, let's quickly take a look at transitions. So if you look at the documentation here, you'll see that there's support for transitions, and it's pretty much the same way that Vue does it, or one of the ways that Vue does it. So as you see, we have these six transition directives which represent different points in the transition. And as you can see, it says it behaves exactly like Vue's transition directives, but they have slightly different names. So let's go ahead and try this and, combined with Tailwind CSS, I'm actually using version 1.2 beta, which has support for transitions. Let's go ahead and try this out.
Yeah, we need these. So let's try it on our dropdown here. So on this right here. Let's go up here... where's my dropdown... avatar.jpg. Okay, so this was actually supposed to be !isOpen. Right now it only turns it on, but if I click it again it won't turn it off. Actually it does, because I'm using the @click.away thing, but we can also change this to !isOpen if you want. It should be the same thing. Cool.
Okay, so yeah, let's add a transition on this. And that's gonna be on the actual dropdown. So right here. Okay. I'll just indent this. You can see the descriptions for where these take place in the documentation here, right here, and you just have to apply the appropriate classes. And like I said, I'm using Tailwind 1.2, which does have some transition classes. So this one we have to transition-all and transition-slow has actually been changed recently to duration and then the duration in milliseconds. So I want it to be actually quite fast. Let's do slow first just so you can see it, so 500 milliseconds.
And this is when the transition starts, so let's say I want it to be slightly smaller and then grow. This is when it ends. Okay, and this is for the opposite. So, let's say transition-all as well, ease-in, and let's change the duration to the same thing. And this will stay the same and this will be 75. Okay, let's see if I did that correctly and see if there's a transition on this. There we go. If you see, there is a fade-in effect here, but the scale effect doesn't seem to be working. As you can see, I added different scales here. I think we have to add transform here. So let's add transform. See if that works. Refresh. There we go. You see it grow from 75 to 100, but it's growing from the middle, which is the default. If we want it to grow from, say, the top right, there is also a class in Tailwind for that. That's just origin-top-right. And now you'll see it grow from the top right. There we go. Cool. And obviously that's pretty slow. I just did that so you can see it. So 100 milliseconds or 150 is what I like. There we go. We have a cool transition.
Applying Transitions to the Accordion
And we can even do something similar to the dropdown here if you want a transition. So let's grab this and let's add it to our FAQ here. And I want the transition on this right here. So let's just fix this up. x-show="isOpen" and put the transition right here. Okay, and see if that works. Refresh. Okay. So the fade works but the transform doesn't work. Let's see if we add transform here, does it... okay, so it does. Cool.
Conclusion
So yeah, I hope that gives you insight on Alpine.js and where you might be able to use it. I personally like it and will be using it in cases like this where I have to toggle some UI components in a server-driven app. Please like, comment, and subscribe if you haven't already done so. Thanks for watching, guys. See you in the next one. Okay, thanks, bye.