DEV Community

Cover image for How to add Tailwind CSS Carousel React (no library)
Aaronn
Aaronn

Posted on • Originally published at frontendshape.com

1 1 1 1 1

How to add Tailwind CSS Carousel React (no library)

In this tutorial, we will see how to add a Tailwind CSS carousel in React without using any library.
See Also: How to Use Carousel Slider in Shadcn UI with Next.js

React with Tailwind CSS Carousel Slider

Modified carousel section: added overflow-hidden class to prevent image overflow, wrapped items in carousel-inner div with flex layout, applied transition-transform and duration-500 classes for smooth transitions, calculated transform property to translate items horizontally, added flex-shrink-0 and w-full classes to prevent shrinking and ensure full width, used picsum.photos for dummy images.

import { useState } from "react";

const Carousel = ({ images }) => {
  const [currentIndex, setCurrentIndex] = useState(0);

  const handlePrevClick = () => {
    setCurrentIndex((currentIndex - 1 + images.length) % images.length);
  };

  const handleNextClick = () => {
    setCurrentIndex((currentIndex + 1) % images.length);
  };

  return (
    <div className="relative">
      <div className="carousel overflow-hidden">
        <div
          className="carousel-inner flex transition-transform duration-500"
          style={{ transform: `translateX(-${currentIndex * 100}%)` }}
        >
          {images.map((image, index) => (
            <div key={index} className="carousel-item flex-shrink-0 w-full">
              <img src={image.src} alt={image.alt} className="w-full h-auto" />
            </div>
          ))}
        </div>
      </div>
      <button
        className="absolute left-0 top-1/2 -translate-y-1/2 bg-gray-300 rounded-full p-2 hover:bg-gray-400 transition-colors duration-300"
        onClick={handlePrevClick}
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          className="h-6 w-6"
          fill="none"
          viewBox="0 0 24 24"
          stroke="currentColor"
        >
          <path
            strokeLinecap="round"
            strokeLinejoin="round"
            strokeWidth={2}
            d="M15 19l-7-7 7-7"
          />
        </svg>
      </button>
      <button
        className="absolute right-0 top-1/2 -translate-y-1/2 bg-gray-300 rounded-full p-2 hover:bg-gray-400 transition-colors duration-300"
        onClick={handleNextClick}
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          className="h-6 w-6"
          fill="none"
          viewBox="0 0 24 24"
          stroke="currentColor"
        >
          <path
            strokeLinecap="round"
            strokeLinejoin="round"
            strokeWidth={2}
            d="M9 5l7 7-7 7"
          />
        </svg>
      </button>
    </div>
  );
};

const App = () => {
  const images = [
    { src: "https://picsum.photos/800/400?random=1", alt: "Image 1" },
    { src: "https://picsum.photos/800/400?random=2", alt: "Image 2" },
    { src: "https://picsum.photos/800/400?random=3", alt: "Image 3" },
  ];

  return (
    <div className="container mx-auto">
      <h1 className="text-3xl font-bold mb-4">My Carousel</h1>
      <Carousel images={images} />
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

react tailwind carousel

React Carousel Slider (Tailwind CSS) - TypeScript

import React, { useState } from 'react';

interface Image {
  src: string;
  alt: string;
}

interface CarouselProps {
  images: Image[];
}

const Carousel: React.FC<CarouselProps> = ({ images }) => {
  const [currentIndex, setCurrentIndex] = useState<number>(0);

  const handlePrevClick = () => {
    setCurrentIndex((currentIndex - 1 + images.length) % images.length);
  };

  const handleNextClick = () => {
    setCurrentIndex((currentIndex + 1) % images.length);
  };

  return (
    <div className="relative">
      <div className="carousel overflow-hidden">
        <div
          className="carousel-inner flex transition-transform duration-500"
          style={{ transform: `translateX(-${currentIndex * 100}%)` }}
        >
          {images.map((image, index) => (
            <div key={index} className="carousel-item flex-shrink-0 w-full">
              <img src={image.src} alt={image.alt} className="w-full h-auto" />
            </div>
          ))}
        </div>
      </div>
      <button
        className="absolute left-0 top-1/2 -translate-y-1/2 bg-gray-300 rounded-full p-2 hover:bg-gray-400 transition-colors duration-300"
        onClick={handlePrevClick}
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          className="h-6 w-6"
          fill="none"
          viewBox="0 0 24 24"
          stroke="currentColor"
        >
          <path
            strokeLinecap="round"
            strokeLinejoin="round"
            strokeWidth={2}
            d="M15 19l-7-7 7-7"
          />
        </svg>
      </button>
      <button
        className="absolute right-0 top-1/2 -translate-y-1/2 bg-gray-300 rounded-full p-2 hover:bg-gray-400 transition-colors duration-300"
        onClick={handleNextClick}
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          className="h-6 w-6"
          fill="none"
          viewBox="0 0 24 24"
          stroke="currentColor"
        >
          <path
            strokeLinecap="round"
            strokeLinejoin="round"
            strokeWidth={2}
            d="M9 5l7 7-7 7"
          />
        </svg>
      </button>
    </div>
  );
};

const App: React.FC = () => {
  const images: Image[] = [
    { src: 'https://picsum.photos/800/400?random=1', alt: 'Image 1' },
    { src: 'https://picsum.photos/800/400?random=2', alt: 'Image 2' },
    { src: 'https://picsum.photos/800/400?random=3', alt: 'Image 3' },
  ];

  return (
    <div className="container mx-auto">
      <h1 className="text-3xl font-bold mb-4">My Carousel</h1>
      <Carousel images={images} />
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

React Tailwind Carousel with Autoplay and Pagination

This carousel has autoplay, pagination dots with a **handleDotClick **function to update the currentIndex, and the active dot is highlighted with a different background color.

import { useState, useEffect } from "react";

const Carousel = ({ images, autoplayInterval = 3000 }) => {
  const [currentIndex, setCurrentIndex] = useState(0);

  useEffect(() => {
    const autoplayTimer = setInterval(() => {
      handleNextClick();
    }, autoplayInterval);

    return () => clearInterval(autoplayTimer);
  }, [currentIndex, autoplayInterval]);

  const handlePrevClick = () => {
    setCurrentIndex((currentIndex - 1 + images.length) % images.length);
  };

  const handleNextClick = () => {
    setCurrentIndex((currentIndex + 1) % images.length);
  };

  const handleDotClick = (index) => {
    setCurrentIndex(index);
  };

  return (
    <div className="relative">
      <div className="carousel overflow-hidden">
        <div
          className="carousel-inner flex transition-transform duration-500"
          style={{ transform: `translateX(-${currentIndex * 100}%)` }}
        >
          {images.map((image, index) => (
            <div key={index} className="carousel-item flex-shrink-0 w-full">
              <img src={image.src} alt={image.alt} className="w-full h-auto" />
            </div>
          ))}
        </div>
      </div>
      <button
        className="absolute left-0 top-1/2 -translate-y-1/2 bg-gray-300 rounded-full p-2 hover:bg-gray-400 transition-colors duration-300"
        onClick={handlePrevClick}
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          className="h-6 w-6"
          fill="none"
          viewBox="0 0 24 24"
          stroke="currentColor"
        >
          <path
            strokeLinecap="round"
            strokeLinejoin="round"
            strokeWidth={2}
            d="M15 19l-7-7 7-7"
          />
        </svg>
      </button>
      <button
        className="absolute right-0 top-1/2 -translate-y-1/2 bg-gray-300 rounded-full p-2 hover:bg-gray-400 transition-colors duration-300"
        onClick={handleNextClick}
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          className="h-6 w-6"
          fill="none"
          viewBox="0 0 24 24"
          stroke="currentColor"
        >
          <path
            strokeLinecap="round"
            strokeLinejoin="round"
            strokeWidth={2}
            d="M9 5l7 7-7 7"
          />
        </svg>
      </button>
      <div className="carousel-dots flex justify-center mt-4">
        {images.map((_, index) => (
          <button
            key={index}
            className={`carousel-dot mx-1 w-3 h-3 rounded-full ${index === currentIndex ? "bg-gray-800" : "bg-gray-400"
              }`}
            onClick={() => handleDotClick(index)}
          />
        ))}
      </div>
    </div>
  );
};

const App = () => {
  const images = [
    { src: "https://picsum.photos/800/400?random=1", alt: "Image 1" },
    { src: "https://picsum.photos/800/400?random=2", alt: "Image 2" },
    { src: "https://picsum.photos/800/400?random=3", alt: "Image 3" },
  ];

  return (
    <div className="container mx-auto">
      <h1 className="text-3xl font-bold mb-4">
        {" "}
        Carousel Autoplay and Pagination
      </h1>
      <Carousel images={images} autoplayInterval={5000} />
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

react tailwind carousel autoplay and pagination

See Also

👉React with Tailwind CSS File Upload Example
👉How to Use Toastify in React with Tailwind CSS
👉Create a Responsive Navbar React Tailwind CSS TypeScript
👉React TypeScript Tailwind CSS Popup Modal Tutorial
👉How to Add Drag-and-Drop Image Upload with Dropzone in React Using Tailwind CSS

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay