DEV Community

Maciej
Maciej

Posted on • Originally published at janowski.dev

Building a carousel component with TailwindCSS and Alpine.js

By the end of this article you will be able to create a carousel component with TailwindCSS and Alpine.js

Here is what a working example will look like

Set up

First add tailwind and alpine.
In the index.html add what's below to your <head>

<script src="https://unpkg.com/tailwindcss-jit-cdn"></script> 
Enter fullscreen mode Exit fullscreen mode

For Tailwind we are using the jit compiler cdn to keep it simple and keep the size small.

<script src="https://unpkg.com/alpinejs" defer></script> 
Enter fullscreen mode Exit fullscreen mode

And then the official alpine.js cdn

Creating the component

Create the main image

<body class="p-4 font-serif bg-gray-50"> <h1 class="text-2xl font-semibold"> TailwindCSS + Alpine.js Carousel </h1> <div class="relative"> <img class="h-64 w-full object-cover object-center" src="https://images.unsplash.com/photo-1527549993586-dff825b37782?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80" alt="mountains" /> </div> </body> 
Enter fullscreen mode Exit fullscreen mode

I used mountain pics as a placeholder for the images.

previous/next buttons

Let's create to big buttons with arrows on each side to switch between items

<img class="h-64 w-full object-cover object-center" src="https://images.unsplash.com/photo-1527549993586-dff825b37782?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80" alt="mountains" /> <button class="absolute inset-y-0 left-0 px-2 py-[25%] h-full w-8 group hover:bg-gray-500 hover:bg-opacity-75 cursor-pointer"> <span class="hidden group-hover:block text-gray-50"> &larr; </span> </button> <button class="absolute inset-y-0 right-0 px-2 py-[25%] h-full w-8 group hover:bg-gray-500 hover:bg-opacity-75 cursor-pointer"> <span class="hidden group-hover:block text-gray-50"> &rarr; </span> </button> 
Enter fullscreen mode Exit fullscreen mode

dot buttons

Next dot buttons to switch between items by index, and also show the selected item

<div class="absolute bottom-0 w-full p-4 flex justify-center space-x-2"> <button class="h-2 w-2 rounded-full bg-gray-300 hover:bg-gray-300 ring-2 ring-gray-300"></button> <button class="h-2 w-2 rounded-full bg-gray-500 hover:bg-gray-300 ring-2 ring-gray-300"></button> <button class="h-2 w-2 rounded-full bg-gray-500 hover:bg-gray-300 ring-2 ring-gray-300"></button> </div> 
Enter fullscreen mode Exit fullscreen mode

Your code should look like this

<div class="relative"> <img class="h-64 w-full object-cover object-center" src="https://images.unsplash.com/photo-1527549993586-dff825b37782?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80" alt="mountains" /> <button class="absolute inset-y-0 left-0 px-2 py-[25%] h-full w-8 group hover:bg-gray-500 hover:bg-opacity-75 cursor-pointer"> <span class="hidden group-hover:block text-gray-50"> &larr; </span> </button> <button class="absolute inset-y-0 right-0 px-2 py-[25%] h-full w-8 group hover:bg-gray-500 hover:bg-opacity-75 cursor-pointer"> <span class="hidden group-hover:block text-gray-50"> &rarr; </span> </button> <div class="absolute bottom-0 w-full p-4 flex justify-center space-x-2"> <button class="h-2 w-2 rounded-full bg-gray-300 hover:bg-gray-300 ring-2 ring-gray-300"></button> <button class="h-2 w-2 rounded-full bg-gray-500 hover:bg-gray-300 ring-2 ring-gray-300"></button> <button class="h-2 w-2 rounded-full bg-gray-500 hover:bg-gray-300 ring-2 ring-gray-300"></button> </div> </div> 
Enter fullscreen mode Exit fullscreen mode

Adding alpine.js

Now for the fun part let's open a script tag before the closing body tag and create our alpine object.

We need two variables:

  • selected to show a current index of image list
  • images array with the list of images we want to show in the carousel.

I will use a couple of mountain landscape images from Unsplash

const carousel = () => { return { selected: 0, images: [ "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80", "https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80", "https://images.unsplash.com/photo-1500534314209-a25ddb2bd429?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=987&q=80", "https://images.unsplash.com/photo-1486870591958-9b9d0d1dda99?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80", "https://images.unsplash.com/photo-1485160497022-3e09382fb310?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80", "https://images.unsplash.com/photo-1472791108553-c9405341e398?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2137&q=80" ] }; }; 
Enter fullscreen mode Exit fullscreen mode

Next let's add x-data property to the top div of our app

<div x-data="carousel()" class="relative"> 
Enter fullscreen mode Exit fullscreen mode

Showing the image

Let's make the image source show the images[selected] image.
Edit the img tag

<img class="h-64 w-full object-cover object-center" :src="images[selected]" alt="mountains" /> 
Enter fullscreen mode Exit fullscreen mode

We removed the src tag and added the :src which is alpnie.js shorthand for x-bind:src

Now your image should show the first image from the images array

Next button

Let's add @click which is alpine's shorthand for x-on:click, and make it increase selected by 1 unless it's the last image then reset it back to 0

<button class="absolute inset-y-0 right-0 px-2 py-[25%] h-full w-8 group hover:bg-gray-500 hover:bg-opacity-75 cursor-pointer"> <span class="hidden group-hover:block text-gray-50"> &rarr; </span> </button> 
Enter fullscreen mode Exit fullscreen mode

Previous button

The back button other way around

<button class="absolute inset-y-0 left-0 px-2 py-[25%] h-full w-8 group hover:bg-gray-500 hover:bg-opacity-75 cursor-pointer"> <span class="hidden group-hover:block text-gray-50"> &larr; </span> </button> 
Enter fullscreen mode Exit fullscreen mode

Dot buttons

First we want to render as many buttons as there are images for that we will use the template tag and alpine x-for

<template x-for="(image,index) in images" :key="index"> <button class="h-2 w-2 rounded-full hover:bg-gray-300 ring-2 ring-gray-300"></button> </template> 
Enter fullscreen mode Exit fullscreen mode

Add @click to set the new index

<template x-for="(image,index) in images" :key="index"> <button @click="selected = index" class="h-2 w-2 rounded-full hover:bg-gray-300 ring-2 ring-gray-300"></button> </template> 
Enter fullscreen mode Exit fullscreen mode

Finally add conditional styling so the button for selected image looks different

<template x-for="(image,index) in images" :key="index"> <button @click="selected = index" :class="{'bg-gray-300': selected == index, 'bg-gray-500': selected != index}" class="h-2 w-2 rounded-full hover:bg-gray-300 ring-2 ring-gray-300"></button> </template> 
Enter fullscreen mode Exit fullscreen mode

Now your component is fully working

What's next?

You could further improve the carousel component by:

  • making it mobile responsive
  • adding animation on image change
  • auto changing the image on interval

Or you can start using the carousel in your projects.

Follow me on Twitter @MaciejJanowski to stay updated on my content.

Top comments (0)