<div id="carousel">
  <button id="prev-btn"><</button>
  <button id="next-btn">></button>
  <img id="image"/>
  <div id="dots-container"></div>
</div>
#carousel {
  border: 1px solid black;
  width: 50%;
  aspect-ratio: 3 / 2;
  position: fixed;
  left: 25%;
  top: 200px;
}

#prev-btn {
  position: absolute;
  top: 46%;
  left: 10px;
  cursor: pointer;
}

#next-btn {
  position: absolute;
  top: 46%;
  right: 10px;
  curson: pointer;
}

img {
  width: 100%;
  height: 100%;
  object-fit:cover;
  object-position:center;
}

#dots-container {
  text-align: center;
  position: absolute;
  bottom: 10px;
  left: 50%;
  transform: translate(-50%);
}

.dot {
  width: 15px;
  height: 15px;
  border: 1px solid black;
  border-radius: 50%;
  margin: 0 3px;
  background-color: rgba(0, 0, 0, 0.2);
  cursor: pointer;
}

.dot.active {
  background-color: rgba(0, 0, 0, 0.8);
}
/*
* https://frontendeval.com/questions/image-carousel
*
* Build an auto-playing image carousel
*/

const carousel = document.getElementById('carousel');
const image = document.getElementById("image");
const prevButton = document.getElementById('prev-btn');
const nextButton = document.getElementById('next-btn');
const dotsContainer = document.getElementById('dots-container');

let imageList;
let curIndex = 0;
let intervalId;

const showNextImage = () => {
  dotsContainer.children[curIndex].classList.remove('active');
  if (curIndex == imageList.length - 1) {
    curIndex = 0;
  } else {
    curIndex++;
  }
  dotsContainer.children[curIndex].classList.add('active');
  image.src = imageList[curIndex];
  clearInterval(intervalId);
  intervalId = setInterval(showNextImage, 3000);
};

const showPrevImage = () => {
  dotsContainer.children[curIndex].classList.remove('active');
  if (curIndex == 0) {
    curIndex = imageList.length - 1;
  } else {
    curIndex--;
  }
  dotsContainer.children[curIndex].classList.add('active');
  image.src = imageList[curIndex];
  clearInterval(intervalId);
  intervalId = setInterval(showNextImage, 3000);
};

const initialize = async () => {
  const endpoint = "https://www.reddit.com/r/aww/top/.json?t=all";
  try {
    // fetch data
    const response = await fetch(endpoint);
    const jsonResponse = await response.json();
    
    // initialize list
    imageList = jsonResponse.data.children.filter((img) => {
      return img.data.url_overridden_by_dest.includes('jpg');
    }).map((img) => {
      return img.data.url_overridden_by_dest;
    });
    
    // create dots
    for (let i = 0; i < imageList.length; i++) {
      let dot = document.createElement('button');
      dot.classList.add('dot');
      dot.id = 'dot' + i;
      dotsContainer.appendChild(dot);
      dot.addEventListener('click', () => {
        clearInterval(intervalId);
        dotsContainer.children[curIndex].classList.remove('active');
        curIndex = i;
        dotsContainer.children[curIndex].classList.add('active');
        image.src = imageList[curIndex];
        intervalId = setInterval(showNextImage, 3000);
      });
    }
    
    // set first image as active
    image.src = imageList[curIndex];
    dotsContainer.children[curIndex].classList.add('active');
    
    // start auto play
    intervalId = setInterval(showNextImage, 3000);
  } catch (error) {
    console.error('Could not fetch data: ', error);
  }
};

initialize();
prevButton.addEventListener('click', showPrevImage);
nextButton.addEventListener('click', showNextImage);
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.