Create responsive slideshow gallery in Reactjs

In this tutorial, we will learn how to create a responsive slideshow gallery in Reactjs.

In the slideshow gallery, all the images are listed below, and when clicked on any it is viewed in the large canvas. It can be navigated with the next and previous buttons as well as you can see in the below image.

Responsive slideshow gallery in Reactjs

This is similar to the Responsive slideshow in Reactjs, except for bulleted dots we will be showing the images.

If we see the component, it can be broken down into three different parts and can be individually tackled.

  • Slide โ€“ Big canvas where images are previewed.
  • Image listing โ€“ All the gallery images are listed and the active one is highlighted.
  • Navigation โ€“ Next and Previous buttons to navigate.

Slide component

We can create the slide component that will take the image URL and caption as input and render them.

const Slide = ({ image_url, caption, active }) => {
  return (
    <div className={`slide ${active ? "active" : ""}`}>
      <img src={image_url} alt={caption} />
      <span>{caption}</span>
    </div>
  );
};

We can then map the array of images for each slide and display only the active one, keeping others hidden. In the active class, we can add animation to show that images are fading in.

const Slider = ({ images }) => {
  const [active, setActive] = useState(0);

  return (
    <div className="slider">
      <div className="slides">
        {images.map((e, i) => (
          <Slide key={e.caption} {...e} active={i === active} />
        ))}
      </div>
    </div>
  );
};

Adding the navigation to the slides

There are two types of navigation that the slideshow will have, one with the next and previous buttons and a second with the images listed at the bottom.

We can have them directly placed under the slides, you can also abstract them in separate components. When any of the images are clicked, update the index in the state setActive that will show the active image in the canvas.

The images are placed in equal sizes, you can update the logic and have them in bigger size and scrollable on the X-axis or horizontally.

Similarly, on the next and previous navigation, update the setActive to the next or previous index.

const Slider = ({ images }) => {
  const [active, setActive] = useState(0);

  const onNext = () => {
    if (active < images.length - 1) {
      setActive(active + 1);
    }
  };

  const onPrev = () => {
    if (active > 0) {
      setActive(active - 1);
    }
  };

  return (
    <div className="slider">
      <div className="slides">
        {images.map((e, i) => (
          <Slide key={e.caption} {...e} active={i === active} />
        ))}
      </div>
      <div className="navigation">
        <div class="navigation-bottom">
          {images.map((e, i) => (
            <img
              className={`preview ${i === active ? "active" : ""}`}
              key={e.caption}
              onClick={() => setActive(i)}
              src={e.image_url}
              alt={e.caption}
              style={{ width: `${100 / images.length}%` }}
            />
          ))}
        </div>
        <div className="navigation-next-prev">
          <div class="next-prev prev" onClick={onPrev}>
            {" "}
            &lt;{" "}
          </div>
          <div class="next-prev next" onClick={onNext}>
            {" "}
            &gt;{" "}
          </div>
        </div>
      </div>
    </div>
  );
};

We can style the components by adding the CSS properties

.App {
  font-family: sans-serif;
  text-align: center;
}

.slider {
  position: relative;
  max-width: 500px;
  margin: 0 auto;
}

.slide {
  position: relative;
  display: none;
}

@keyframes fade {
  from {
    opacity: 0.4;
  }
  to {
    opacity: 1;
  }
}

.slide.active {
  display: block;
  animation-name: fade;
  animation-duration: 1.5s;
}

.slide span {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  color: #fff;
}

.slide img {
  width: 100%;
}

.navigation-bottom {
  display: flex;
  align-items: center;
  justify-content: center;
}

.preview {
  margin: 0 2px;
  transition: all 0.2s ease;
  cursor: pointer;
  border: 3px solid gray;
}

.preview.active {
  border-color: skyblue;
}

.navigation-next-prev .next-prev {
  position: absolute;
  top: 50%;
  font-size: 1.5em;
  cursor: pointer;
  transform: translateY(-100%);
  z-index: 10000;
}

.next {
  right: 10px;
}

.prev {
  left: 10px;
}

Calling the responsive slideshow gallery with an array of images

import "./styles.css";
import { useState } from "react";

export default function App() {
  const images = [
    {
      image_url:
        "https://img.freepik.com/free-photo/young-female-jacket-shorts-presenting-comparing-something-looking-confident-front-view_176474-37521.jpg?w=1800&t=st=1693037944~exp=1693038544~hmac=97e967909706f9b73b4b47d521acf54806f4b9b3efab6196bc8a69f07efff554",
      caption: "Image 1"
    },
    {
      image_url:
        "https://img.freepik.com/free-photo/girl-grey-shirt-showing-something-her-hand_144627-51099.jpg?t=st=1693037931~exp=1693038531~hmac=63713e5a5cf2d23f53ca82b9996ad224ac6e92d0275a53b6debbe6523d7df020",
      caption: "Image 2"
    },
    {
      image_url:
        "https://img.freepik.com/free-photo/young-lady-shirt-jacket-making-scales-gesture-looking-cheerful-front-view_176474-85195.jpg?t=st=1693037931~exp=1693038531~hmac=2f83b6689538e4056912c96f448163e9ef10998f48f671b7e50279f81611fbe6",
      caption: "Image 3"
    },
    {
      image_url:
        "https://img.freepik.com/free-photo/girl-wide-opening-hands-giving-explanation-high-quality-photo_144627-60466.jpg?w=1800&t=st=1693038021~exp=1693038621~hmac=d4520cd86b2aea3e5dda765ede05bb53d70e18a574756d0f41a6806fe325d26d",
      caption: "Image 4"
    },
    {
      image_url:
        "https://img.freepik.com/free-photo/young-lady-shirt-jacket-making-scales-gesture-looking-cheerful-front-view_176474-85195.jpg?t=st=1693037931~exp=1693038531~hmac=2f83b6689538e4056912c96f448163e9ef10998f48f671b7e50279f81611fbe6",
      caption: "Image 5"
    },
    {
      image_url:
        "https://img.freepik.com/free-photo/girl-wide-opening-hands-giving-explanation-high-quality-photo_144627-60466.jpg?w=1800&t=st=1693038021~exp=1693038621~hmac=d4520cd86b2aea3e5dda765ede05bb53d70e18a574756d0f41a6806fe325d26d",
      caption: "Image 6"
    }
  ];
  return (
    <div className="App">
      <Slider images={images} />
    </div>
  );
}