DEV Community

Saurabh Mahajan
Saurabh Mahajan

Posted on

Tabs using Tailwind and AlpineJs

In this tutorial, we are going to implement the Tab Component using Tailwind CSS and Alpine JS. Tutorial assumes that you have a basic understanding of both Tailwind CSS and JS and have them setup in a Project.

We are going to have 3 Tabs each with its unique content. We will first of all define the Tabs. We are going to use grid class. Since there are 3 tabs we will use grid-cols-3 class.

<div class="grid grid-cols-3 cursor-pointer font-bold">
    <div>First</div>
    <div>Second</div>
    <div>Third</div>
</div>
Enter fullscreen mode Exit fullscreen mode

We have also used cursor-pointer class so that the cursor changes to pointer and font-bold class to make the Headings Bold. At this stage the Result looks like this.

Preview

Next we will apply classes to these Tabs to design them. We will add border, border-black, rounded-t-lg and px-4 classes to each of these div. The first 2 classes apply black border. rounded-t-lg makes sure that the upper left and upper right corners of the div are rounded. px-4 just applies some left and right padding. At this stage our HTML and output looks like below:

<div class="grid grid-cols-3 cursor-pointer font-bold">
    <div class="border border-black rounded-t-lg px-4">First</div>
    <div class="border border-black rounded-t-lg px-4">Second</div>
    <div class="border border-black rounded-t-lg px-4">Third</div>
</div>
Enter fullscreen mode Exit fullscreen mode

Preview

Next we will apply white background and blue text to the first tab, which would be active by default. We will use bg-white and text-blue-700 classes for it. For inactive Tabs, we will use blue background and white text using the classes bg-blue-700 and text-white.

<div class="grid grid-cols-3 cursor-pointer font-bold">
    <div class="border border-black rounded-t-lg px-4 bg-white text-blue-700">First</div>
    <div class="border border-black rounded-t-lg px-4 bg-blue-700 text-white">Second</div>
    <div class="border border-black rounded-t-lg px-4 bg-blue-700 text-white">Third</div>
</div>
Enter fullscreen mode Exit fullscreen mode

Preview

Before we continue further, lets also include AlpineJS. We will wrap the above HTML in a div.

<div x-data="tabs">
    ....
</div>
Enter fullscreen mode Exit fullscreen mode

Here we have used x-data and specified tabs. So we will need define this function. This function will hold all the properties and methods related to Tabs Component.

function tabs() {
    return {
        active: 1,
    }
}
Enter fullscreen mode Exit fullscreen mode

Here we have defined the property active which would define the active Tab and we have given it a default value of 1. We would also define a method which would tell us if the given Tab is active or not.

function tabs() {
    return {
        active: 1,
        isActive(tab) {
            return tab == this.active;
        },
    }
}
Enter fullscreen mode Exit fullscreen mode

Next we will use this isActive Method and :class Alpine Directive to dynamically apply classes to our Tabs.

<div class="border border-black rounded-t-lg px-4"
    :class="isActive(1) ? 'bg-white text-blue-700': 'bg-blue-700 text-white'"
>First</div>
Enter fullscreen mode Exit fullscreen mode

Overall HTML looks like below.

<div x-data="tabs">
    <div class="grid grid-cols-3 cursor-pointer font-bold">
        <div class="border border-black rounded-t-lg px-4"
            :class="isActive(1) ? 'bg-white text-blue-700': 'bg-blue-700 text-white'"
        >First</div>
        <div class="border border-black rounded-t-lg px-4"
            :class="isActive(2) ? 'bg-white text-blue-700': 'bg-blue-700 text-white'"
        >Second</div>
        <div class="border border-black rounded-t-lg px-4"
            :class="isActive(3) ? 'bg-white text-blue-700': 'bg-blue-700 text-white'"
        >Third</div>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Next we will change the value of active property when User Clicks on it. We will define a setActive Method in JS.

    setActive(value) {
        this.active = value;
    }
Enter fullscreen mode Exit fullscreen mode

We will call this method when User clicks on the Tab. We are going to use @click Alpine Directive.

<div class="border border-black rounded-t-lg px-4"
    :class="isActive(1) ? 'bg-white text-blue-700': 'bg-blue-700 text-white'"
    @click="setActive(1)"
>First</div>
Enter fullscreen mode Exit fullscreen mode

At this stage User should be able to change the Tab by clicking on it and the Active Tab Classes should change accordingly. Next we will define the Contents of the Tab.

<div class="border border-black p-4 rounded-b-lg">
    <div>
        This is First Tab.
    </div>
    <div>
        This is Second Tab.
    </div>
    <div>
        This is Tab Tab.
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Currently all Contents are showing. We can show / hide the contents based on the active tab. We will use the x-show directive and the same isActive Method.

<div x-show="isActive(1)">
    This is First Tab.
</div>
<div x-show="isActive(2)">
    This is Second Tab.
</div>
<div x-show="isActive(3)">
    This is Third Tab.
</div>
Enter fullscreen mode Exit fullscreen mode

At this stage, our Tab Functionality will be working correctly. We can further improve UI this using the x-transition directive.

<div x-show="isActive(1)" x-transition>
    This is First Tab.
</div>
Enter fullscreen mode Exit fullscreen mode

You will see that this gives a bit of flicker effect. We can fix it by changing x-transition to x-transition:enter.duration.500ms.

Our HTML at this stage looks like below:

<div x-data="tabs">
    <div class="grid grid-cols-3 cursor-pointer font-bold">
        <div class="border border-black rounded-t-lg px-4"
            :class="isActive(1) ? 'bg-white text-blue-700': 'bg-blue-700 text-white'"
            @click="setActive(1)"
        >First</div>
        <div class="border border-black rounded-t-lg px-4"
            :class="isActive(2) ? 'bg-white text-blue-700': 'bg-blue-700 text-white'"
            @click="setActive(2)"
        >Second</div>
        <div class="border border-black rounded-t-lg px-4"
            :class="isActive(3) ? 'bg-white text-blue-700': 'bg-blue-700 text-white'"
            @click="setActive(3)"
        >Third</div>
    </div>
    <div class="border border-black p-4 rounded-b-lg">
        <div x-show="isActive(1)" x-transition:enter.duration.500ms>
            This is First Tab.
        </div>
        <div x-show="isActive(2)" x-transition:enter.duration.500ms>
            This is Second Tab.
        </div>
        <div x-show="isActive(3)" x-transition:enter.duration.500ms>
            This is Third Tab.
        </div>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

We see a bit of duplicating classes for Active Tab. We can define a getClasses method as below:

getClasses(tab) {
    if(this.isActive(tab)) {
        return 'bg-white text-blue-700';
    }
    return 'bg-blue-700 text-white';
}
Enter fullscreen mode Exit fullscreen mode

Our HTML now becomes

<div x-data="tabs">
    <div class="grid grid-cols-3 cursor-pointer font-bold">
        <div class="border border-black rounded-t-lg px-4" :class="getClasses(1)"
            @click="setActive(1)">First</div>
        <div class="border border-black rounded-t-lg px-4" :class="getClasses(2)"
            @click="setActive(2)">Second</div>
        <div class="border border-black rounded-t-lg px-4" :class="getClasses(2)"
            @click="setActive(3)">Third</div>
    </div>
    <div class="border border-black p-4 rounded-b-lg">
        <div x-show="isActive(1)" x-transition:enter.duration.500ms>
            This is First Tab.
        </div>
        <div x-show="isActive(2)" x-transition:enter.duration.500ms>
            This is Second Tab.
        </div>
        <div x-show="isActive(3)" x-transition:enter.duration.500ms>
            This is Third Tab.
        </div>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

And our Tab should be working fine like below:

Preview

Hope you have enjoyed this Article. For similar articles, you can follow me on Twitter

Discussion (0)