DEV Community

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

Posted on • Originally published at frontendshape.com

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

Top comments (0)