Extract UI Components with AlpineJS and TailwindCSS using x-spread and @apply

Alpine and Tailwind are made to work in the markup itself. But let's break the rules here and extract components into their separate CSS and JS. Let's see how it can be useful in your web applications.

Extract UI Components with AlpineJS and TailwindCSS using x-spread and @apply
Karthik Kamalakannan

Karthik Kamalakannan

Founder and CEO

Today we are going to create a dropdown component using AlpineJS and TailwindCSS.

AlpineJS is a simple JavaScript toolkit for creating reactive components. TailwindCSS is an utility based CSS framework. You can use both these frameworks in the HTML markup itself. But for some repeating components, you can extract it as a separate component so that you can reuse it.

Note: The following example doesn’t follow accessibility principles to keep it simple. Make sure you follow accessibility principles for production websites.

Check out this gist for full source code.

HTML

Open a new html file in your website and add the following snippet.

<div class="dropdown">
<button class="dropdown-trigger" id="open-color-menu">Open Dropdown</button>
<div class="dropdown-list" id="color-menu">
<a href="#" class="dropdown-item">Red</a>
<a href="#" class="dropdown-item">Blue</a>
<a href="#" class="dropdown-item">Green</a>
</div>
</div>

CSS

Let’s start with all the CSS that we need, I assume you have already set up a Tailwind integrated website. So in your CSS file, you can add this.

We use a special @apply function here that is available from TailwindCSS. It’s used to inline any Tailwind utility classes into our own custom CSS.

[x-cloak] {
@apply hidden;
}
.dropdown-trigger {
@apply inline-block rounded-md bg-purple-700 px-4 py-2 text-white;
}
.dropdown-list {
@apply absolute z-10 flex w-56 flex-col rounded border border-solid border-gray-200 bg-white p-2 shadow-md;
}
.dropdown-item {
@apply relative flex items-center px-2 py-1 text-gray-800;
}

JS

Next, we can use Alpine to give our dropdown that sweet interactivity. Make sure you already have AlpineJS defined and then change your dropdown markup to this.

<div x-data="dropdown()">
<button class="dropdown-trigger" id="open-color-menu" x-spread="trigger">
Open Dropdown
</button>
<div class="dropdown-list" id="color-menu" x-spread="dropdown" x-cloak>
<a href="#" class="dropdown-item">Red</a>
<a href="#" class="dropdown-item">Blue</a>
<a href="#" class="dropdown-item">Green</a>
</div>
</div>

Here, x-data is the encapsulating function, the x-spread attributes will allow us to bind the object of Alpine directives to an this element so that we can reuse it everywhere.

And x-cloak hides the dropdown list before Alpine is defined. So we won’t see the dropdown list and then hide on page load.

And then add this to a script file in your website:

window.dropdown:function () {
return {
open: false,
trigger: {
["@keydown.escape"]() {
this.open:false;
},
["@click"]() {
this.open:true;
},
},
dropdown: {
["@keydown.escape"]() {
this.open:false;
},
["x-show.transition"]() {
return this.open;
},
["@click.away"]() {
this.open:false;
},
},
};
};

When you click on the dropdown trigger,

  • The @click directive makes the open variable true.
  • When the open variable is true, the dropdown will show because of the x-show.transition directive, where transition will add a little animation while opening up.

When you click outside or press escape button,

  • The @click.away and @keydown.escape directives will make the open variable false.
  • It will make the same x-show.transition hide the dropdown element.


And that’s it, you can use this markup everywhere in your website and it will work for you. If you need to change CSS or JS in this component, you have to do it just once.

Check out this gist for the full source code.