Building a Custom Image Carousel with Vanilla JavaScript

HTML Structure

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Carousel</title>
    <link rel="stylesheet" href="styles/carousel.css">
</head>
<body>
    <div class="carousel-container">
        <div class="slide-track">
            <img src="https://example-image-1.jpg" alt="Nature Scene 1">
            <img src="https://example-image-2.jpg" alt="Nature Scene 2">
            <img src="https://example-image-3.jpg" alt="Nature Scene 3">
            <img src="https://example-image-4.jpg" alt="Nature Scene 4">
        </div>
        <span class="nav-left">&lt;</span>
        <span class="nav-right">&gt;</span>
        <div class="indicator-dots">
            <button class="active-dot"></button>
            <button></button>
            <button></button>
            <button></button>
        </div>
    </div>
    <script src="scripts/carousel.js"></script>
</body>
</html>

CSS Styling

* {
    margin: 0;
    padding: 0;
}

ul, li, ol {
    list-style: none;
}

button {
    cursor: pointer;
    border: none;
    background-color: rgba(255, 255, 255, 1);
}

.carousel-container {
    width: 800px;
    height: 400px;
    overflow: hidden;
    border: 1px solid #ccc;
    margin: 100px auto;
    position: relative;
}

.slide-track {
    width: 3200px;
    height: 400px;
    display: flex;
    position: absolute;
    left: 0;
    top: 0;
}

img {
    width: 800px;
    height: 400px;
}

span {
    position: absolute;
    width: 50px;
    height: 50px;
    text-align: center;
    line-height: 50px;
    top: 175px;
    color: #f00;
    font-size: 30px;
}

.nav-left {
    left: 20px;
}

.nav-right {
    right: 20px;
}

.indicator-dots {
    width: 90px;
    height: 15px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    position: absolute;
    left: calc(50% - 45px);
    bottom: 20px;
}

.indicator-dots button {
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: #ccc;
}

.active-dot {
    background: #04beff;
}

JavaScript Functionality

const trackElement = document.querySelector('.slide-track');
const leftButton = document.querySelector('.nav-left');
const rightButton = document.querySelector('.nav-right');
const dotsContainer = document.querySelector('.indicator-dots');
const indicatorButtons = document.querySelectorAll('.indicator-dots button');

let currentPosition = 0;
let slideInterval;

function updateIndicators() {
    indicatorButtons.forEach((btn, index) => {
        btn.classList.remove('active-dot');
    });
    
    const activeIndex = Math.abs(currentPosition / 800);
    if (activeIndex < indicatorButtons.length) {
        indicatorButtons[activeIndex].classList.add('active-dot');
    }
}

function startAutoSlide() {
    slideInterval = setInterval(() => {
        currentPosition -= 800;
        if (currentPosition < -2400) {
            currentPosition = 0;
        }
        trackElement.style.left = currentPosition + 'px';
        updateIndicators();
    }, 2500);
}

startAutoSlide();

leftButton.addEventListener('click', () => {
    currentPosition -= 800;
    if (currentPosition < -2400) {
        currentPosition = 0;
    }
    trackElement.style.left = currentPosition + 'px';
    clearInterval(slideInterval);
    startAutoSlide();
    updateIndicators();
});

rightButton.addEventListener('click', () => {
    currentPosition += 800;
    if (currentPosition > 0) {
        currentPosition = -2400;
    }
    trackElement.style.left = currentPosition + 'px';
    clearInterval(slideInterval);
    startAutoSlide();
    updateIndicators();
});

indicatorButtons.forEach((dot, index) => {
    dot.addEventListener('click', () => {
        indicatorButtons.forEach(btn => btn.classList.remove('active-dot'));
        dot.classList.add('active-dot');
        currentPosition = index * -800;
        trackElement.style.left = currentPosition + 'px';
        clearInterval(slideInterval);
        startAutoSlide();
        updateIndicators();
    });
});

This carousel implementation uses pure vanilla JavaScript, HTML, and CSS without any external dependencies. The component features automatic sliding functionality, manual navigasion controls, and interactive indicator dots that allow users to jump to specific slides. The structure can be easily adapted for use in modern frameworks like Vue.js by wrapping the funtcionality in a reusable component.

Tags: javascript Carousel slider vanilla-js html

Posted on Mon, 27 Jul 2026 16:43:21 +0000 by Gmunky