DEV Community

Cover image for Carousel with Vanilla JavaScript
Mark Abeto
Mark Abeto

Posted on

Carousel with Vanilla JavaScript

Hi Guys Good Day!

Today we're gonna make a Carousel using Vanilla JavaScript. Most of my posts we're about fundamentals and concepts and I've realized I haven't made a post about Implementing stuff or something like that. So today I'm gonna change that. So I've decided to make this post because as of now I'm currently finding a new job and one of the companies that I've applied to has an exam. And in that exam, one of the functionalities that I have to make is an Image Carousel and one of the rules of the exam is that I have to implement it without using existing javascript carousel libraries instead I have to choose one of these technologies that I'm gonna use for the Carousel. React, jQuery, Angular and Vue. I choose React because I love working with React and I want to finish the exam fast. So now, I want to implement it using with just JavaScript. Let's get to the coding stuff.

Our images taken from pexels.com.

1.jpeg
Image 1
2.jpeg
Image 2
3.jpeg
Image 3

Our index.html file.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Carousel using Vanilla JS</title>
  <link href="./styles.css">
</head>

<body>
  <div class="carousel">
    <div class="arrow-left">
      <span class="arrow">&#x2039;</span>
    </div>
    <img src="./1.jpeg" alt="Carousel Image">
    <div class="arrow-right">
      <span class="arrow">&#x203A;</span>
    </div>
    <div class="indicators">
      <span class="active"></span>
      <span></span>
      <span></span>
    </div>
  </div>

  <script type="text/javascript" src="./carousel.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

This the primary structure of our html. All the elements that we use are inside the div element with a class of carousel.

Our styles.css file.

.arrow {
  font-size: 51px;
  font-weight: bold;
  border-radius: 50%;
  width: 50px;
  height: 65px;
  color: white;
  text-align: center;
  display: inline-block;
  transition: all 0.3s ease;
}

.arrow:hover {
  color: #121212;
  background: white;
  cursor: pointer;
}


.carousel {
  position: relative;
  display: block;
  width: 600px;
  margin: 0 auto;
  margin-top: 5%;
}

.arrow-left {
  position: absolute;
  left: 0;
  top: 50%;
  margin-left: 5px;
  transform: translateY(-50%);
}

.arrow-right {
  position: absolute;
  right: 0;
  top: 50%;
  margin-right: 5px;
  transform: translateY(-50%);
}

.carousel>img {
  width: 100%;
  height: 450px;
  border-radius: 4px;
}

.d-none {
  display: none;
}

.indicators {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 0;
  margin-bottom: 10px;
}

.indicators>span {
  display: inline-block;
  border-radius: 50%;
  width: 20px;
  height: 20px;
  background: white;
}

.indicators>span.active {
  background: #4fc355;
}
Enter fullscreen mode Exit fullscreen mode

I'm not pretty good with my css skills (sorry), so bear with me our carousel div element has a position: relative; style, so that we can position our arrows and indicators in the correct positions using the position: absolute inside the our carousel container.

So let's take a look at our carousel.js file. So, I'm gonna divide our js file into multiple sections so I can explain it clearly.

First Section

const arrowLeft = document.querySelector('.arrow-left');
const arrowRight = document.querySelector('.arrow-right');
const imgCarousel = document.querySelector('img');
const indicators = document.querySelectorAll('.indicators > span');
const images = ['./1.jpeg', './2.jpeg', './3.jpeg'];
Enter fullscreen mode Exit fullscreen mode

The first part is declaring and selecting the elements that we gonna use in our
carousel. I use the document.querySelector and document.querySelectorAll method in the document object because it's more flexible than the other method in the document object for
selecting elements. And our images variable which holds the relative paths of our images, assuming we have the same files. You can change these filenames depending in your files.

Second Section


const setAttr = (el, attr, value) => el.setAttribute(attr, value);
const getAttr = (el, attr) => el.getAttribute(attr);

const getImageIndex = (image) => images.indexOf(image)

const getCurrentImageIndex = () => {
  const currentImage = getAttr(imgCarousel, 'src');
  return getImageIndex(currentImage);
};

const getArrowLeftImageIndex = (currentIndex) => {
  return currentIndex === 0 ? 2 : currentIndex - 1;
};

const getArrowRightImageIndex = (currentIndex) => {
  return currentIndex === 2 ? 0 : currentIndex + 1;
};

const activateIndicator = (index) => {
  indicators.forEach((el, i) => {
    if (el.classList.contains('active')) {
      el.classList.remove('active')
    };
    if (index === i) el.classList.add('active');
  })
};
Enter fullscreen mode Exit fullscreen mode

Our helper functions. The first two functions are used for setting and getting respectively the attribute of the element we want. In this case, will be the img element. The third function is pretty straightforward it's for getting the index of the image. The fourth function is pretty much the same as the third the difference is that here is that we get the image source here and call the getImageIndex function and return the result. The fourth function getArrowLeftImageIndex is used for clicking the left arrow and fifth function getArrowRightImageIndex
is used for clicking the right arrow. And lastly the activateIndicator function is used for updating the correct indicator's class.

Third Section

const intervalSlider = (direction, delay = 1000) => {
  let callback = null, getNewIndexFunc = null;
  if (direction === 'left') {
    getNewIndexFunc = () => getArrowLeftImageIndex(getCurrentImageIndex());

  } else {
    getNewIndexFunc = () => getArrowRightImageIndex(getCurrentImageIndex());
  }

  callback = () => {
    let newIndex = getNewIndexFunc();
    activateIndicator(newIndex);
    setAttr(imgCarousel, 'src', images[newIndex]);
  }

  return () => setInterval(callback, delay);
}
Enter fullscreen mode Exit fullscreen mode

So our third section is just one function. This function is used for sliding functionality of our carousel. Basically what this function does is that when we pass the direction parameter with a value of "left" we're gonna get the function that calculates the image index when clicking
the left (<) arrow and we're gonna use that function inside the callback to calculate the new index of the previous image and update the correct indicator and the correct image based on the newIndex.
If we pass a value of "right" for the direction
parameter we're gonna get the function that calculates the next image when clicking the right (>) arrow. The intervalSlider returns the interval that we're gonna use inside our click events and also you can change
the delay but my default is 1 second.

Fourth Section


const leftInterval = intervalSlider('left');
const rightInterval = intervalSlider('right');

let left = null, right = null;

arrowLeft.addEventListener('click', (e) => {
  const newIndex = getArrowLeftImageIndex(getCurrentImageIndex());
  activateIndicator(newIndex);
  right && clearInterval(right);
  if (!left) {
    left = leftInterval()
  }
  setAttr(imgCarousel, 'src', images[newIndex]);
});
arrowRight.addEventListener('click', (e) => {
  const newIndex = getArrowRightImageIndex(getCurrentImageIndex());
  activateIndicator(newIndex);

  left && clearInterval(left);
  if (!right) {
    right = rightInterval();
  }
  setAttr(imgCarousel, 'src', images[newIndex]);
});
Enter fullscreen mode Exit fullscreen mode

Lastly, our fourth section. First we declare the functions that returns the interval and we have the left and right variables to hold the interval so that we can use them later in our click events. So in our arrowLeft click event callback, we get the new index
specifically the previous index of the current index, after that we call the activateIndicator function passing the newIndex. If we have an interval value for the right value, we're gonna clear
that interval using the clearInterval function. After that, if our left variable does not have a value, we're gonna start the interval using the leftInterval and lastly we're gonna update the
image. In our arrowRight click event callback has almost have the same logic as the arrowLeft click event callback, but in the arrowRight we get the next index of the current index and also we're
gonna clear the interval of the left variable if it has a value and start the right interval if it's not already started. After that, update the image.

You can add additional functionalities to this carousel, like pausing or anything that comes up in your mind.

Thanks guys for reading this post.

Have a Nice Day 😃!.

Top comments (3)

Collapse
 
veggigit profile image
veggi

thx.

Collapse
 
macmacky profile image
Mark Abeto

No problem man.

Collapse
 
iisalazar profile image
Ian Salazar

If you don't mind, may I ask for the source code for this?