React Carousel Slider with Thumbnails

React Carousel Slider with Thumbnails component

Learn how to build a responsive carousel with React Bootstrap 5. Tutorial & templates for image gallery slider with thumbnails. Vertical carousel example included.


Basic example

A simple react bootstrap slider with arrows and thumbnails as controls.

import React, { useCallback, useRef, useState } from "react";
import {
  MDBCarousel,
  MDBCarouselInner,
  MDBCarouselItem,
  MDBCarouselElement,
  MDBContainer,
} from "mdb-react-ui-kit";

export default function App() {
  const [currentSlide, setCurrentSlide] = useState(0);

  const carouselInner = useRef(null);

  const slideChanged = useCallback(() => {
    const activeItem = carouselInner.current.querySelector(".active");
    setCurrentSlide(
      Array.from(carouselInner.current.children).indexOf(activeItem)
    );
  }, []);

  const changeSlide = useCallback((position) => {
    Array.from(carouselInner.current.children).forEach((el, i) => {
      if (i !== position) {
        el.classList.remove("active");
      } else {
        el.classList.add("active");
        slideChanged();
      }
    });
  }, []);

  return (
    <MDBContainer className="mt-5">
      <MDBCarousel
        id="carouselExampleIndicators"
        showControls
        fade
        onSlide={slideChanged}
      >
        <MDBCarouselInner ref={carouselInner}>
          <MDBCarouselItem className="active">
            <MDBCarouselElement
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(88).webp"
              alt="..."
            />
          </MDBCarouselItem>

          <MDBCarouselItem>
            <MDBCarouselElement
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(121).webp"
              alt="..."
            />
          </MDBCarouselItem>

          <MDBCarouselItem>
            <MDBCarouselElement
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(31).webp"
              alt="..."
            />
          </MDBCarouselItem>
        </MDBCarouselInner>

        <div className="carousel-indicators" style={{ marginBottom: "-20px" }}>
          <button
            className={`carousel-indicator ${currentSlide === 0 ? "active" : ""}`}
            onClick={() => changeSlide(0)}
            style={{ width: "100px" }}
          >
            <img
              className="d-block w-100 img-fluid"
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(88).webp"
            />
          </button>
          <button
            className={`carousel-indicator ${currentSlide === 1 ? "active" : ""}`}
            onClick={() => changeSlide(1)}
            style={{ width: "100px" }}
          >
            <img
              className="d-block w-100 img-fluid"
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(121).webp"
            />
          </button>
          <button
            className={`carousel-indicator ${currentSlide === 2 ? "active" : ""}`}
            onClick={() => changeSlide(2)}
            style={{ width: "100px" }}
          >
            <img
              className="d-block w-100 img-fluid"
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(31).webp"
            />
          </button>
        </div>
      </MDBCarousel>
    </MDBContainer>
  );
}
.carousel-indicators .carousel-indicator {
  box-sizing: content-box;
  flex: 0 1 auto;
  width: 30px;
  height: 3px;
  padding: 0;
  margin-right: 3px;
  margin-left: 3px;
  text-indent: -999px;
  cursor: pointer;
  background-color: #fff;
  background-clip: padding-box;
  border: 0;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  opacity: .5;
  transition: opacity .6s ease;
}

.carousel-indicators .carousel-indicator.active {
  opacity: 1;
}

Material Design styling

This carousel looks more pleasant thanks to the rounded corners and shadow applied in accordance with Material Design guidelines.

import React, { useCallback, useRef, useState } from "react";
import {
  MDBCarousel,
  MDBCarouselInner,
  MDBCarouselItem,
  MDBCarouselElement,
  MDBContainer,
} from "mdb-react-ui-kit";

export default function Styled() {
  const [currentSlide, setCurrentSlide] = useState(0);

  const carouselInner = useRef(null);

  const slideChanged = useCallback(() => {
    const activeItem = carouselInner.current.querySelector(".active");
    setCurrentSlide(
      Array.from(carouselInner.current.children).indexOf(activeItem)
    );
  }, []);

  const changeSlide = useCallback((position) => {
    Array.from(carouselInner.current.children).forEach((el, i) => {
      if (i !== position) {
        el.classList.remove("active");
      } else {
        el.classList.add("active");
        slideChanged();
      }
    });
  }, []);

  return (
    <MDBContainer className="mt-5">
      <MDBCarousel
        id="carouselExampleIndicators"
        showControls
        fade
        onSlide={slideChanged}
      >
        <MDBCarouselInner ref={carouselInner} className="rounded-3 shadow-1-strong">
          <MDBCarouselItem className="active">
            <MDBCarouselElement
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(88).webp"
              alt="..."
            />
          </MDBCarouselItem>

          <MDBCarouselItem>
            <MDBCarouselElement
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(121).webp"
              alt="..."
            />
          </MDBCarouselItem>

          <MDBCarouselItem>
            <MDBCarouselElement
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(31).webp"
              alt="..."
            />
          </MDBCarouselItem>
        </MDBCarouselInner>

        <div className="carousel-indicators" style={{ marginBottom: "-20px" }}>
          <button
            className={`carousel-indicator ${currentSlide === 0 ? "active" : ""}`}
            onClick={() => changeSlide(0)}
            style={{ width: "100px" }}
          >
            <img
              className="d-block w-100 img-fluid shadow-1-strong rounded"
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(88).webp"
            />
          </button>
          <button
            className={`carousel-indicator ${currentSlide === 1 ? "active" : ""}`}
            onClick={() => changeSlide(1)}
            style={{ width: "100px" }}
          >
            <img
              className="d-block w-100 img-fluid shadow-1-strong rounded"
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(121).webp"
            />
          </button>
          <button
            className={`carousel-indicator ${currentSlide === 2 ? "active" : ""}`}
            onClick={() => changeSlide(2)}
            style={{ width: "100px" }}
          >
            <img
              className="d-block w-100 img-fluid shadow-1-strong rounded"
              src="https://mdbootstrap.com/img/Photos/Slides/img%20(31).webp"
            />
          </button>
        </div>
      </MDBCarousel>
    </MDBContainer>
  );
}
.carousel-indicators .carousel-indicator {
  box-sizing: content-box;
  flex: 0 1 auto;
  width: 30px;
  height: 3px;
  padding: 0;
  margin-right: 3px;
  margin-left: 3px;
  text-indent: -999px;
  cursor: pointer;
  background-color: #fff;
  background-clip: padding-box;
  border: 0;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  opacity: .5;
  transition: opacity .6s ease;
}

.carousel-indicators .carousel-indicator.active {
  opacity: 1;
}