JavaScript image slider with responsive landscape slides and navigation controls
Blog

Build an Accessible JavaScript Image Slider

A JavaScript image slider presents a sequence of images in a compact, touch-friendly area. This tutorial builds a responsive carousel with previous and next controls, slide dots, keyboard navigation, optional autoplay, and reduced-motion support. It uses plain HTML, CSS, and JavaScript—no library or build step.

Quick answer: keep the slides in the document, track the active slide with one JavaScript index, and update both the visible slide and its indicator whenever a visitor uses a control.

Try the interactive JavaScript image slider

What this JavaScript image slider includes

  • Five original landscape scenes that ship with the download.
  • Previous and next controls, plus slide dots for direct navigation.
  • Keyboard support for the left and right arrow keys.
  • Optional autoplay that visitors can start or pause.
  • Responsive layout and support for reduced-motion preferences.

1. Add the slider structure in HTML

Use a labelled carousel region and mark every slide with its position. Give each image descriptive alternative text. Keep the slide captions readable and provide a button for each navigation action. The highlighter below shows the core structure; the ZIP contains all five slides and the complete markup.

2. Style the carousel with responsive CSS

Place each slide in the same frame and reveal only the active one. The example below sets a wide aspect ratio, transitions between slides, and disables movement for people who request reduced motion. The downloadable stylesheet also adjusts the frame on small screens.

3. Control slides with vanilla JavaScript

Track one active index and wrap it at each end of the list. When the index changes, update the slide visibility and active dot together. Connect the same function to the buttons, dots, and arrow keys. The example below is the core navigation logic; the live demo and ZIP include the complete controls.

How to run the complete example

  1. Download the ZIP file and extract it.
  2. Open index.html in a modern browser. It works without a build step or external packages.
  3. Update the captions and image descriptions, then replace the sample SVG files with your own optimized images.

Accessibility and performance tips

Autoplay is off initially, and visitors can start or pause it themselves. Keep visible keyboard focus, use specific image descriptions, and respect the reduced-motion preference. Compress images to suit their display size, and avoid rapidly moving content that cannot be paused.

Common problems

  • Buttons do nothing: check that the JavaScript loads after the slider and the selectors match.
  • The wrong dot stays active: update the active slide and dot in the same function.
  • Images crop unexpectedly: adjust object-fit and the frame aspect ratio.
  • Autoplay ignores reduced motion: check the preference before starting its timer.

Frequently asked questions

Does this image slider require jQuery?

No. The example uses standard browser APIs and vanilla JavaScript.

Can I use my own images?

Yes. Replace the sample SVGs in the images folder and provide meaningful alt text.

How can I make the slider autoplay?

The demo has an optional autoplay control. Keep it easy to pause and do not start it automatically on page load.

Conclusion

This accessible JavaScript image slider is a lightweight starting point for galleries, featured work, or a small hero carousel. Use the formatted code widgets as a guide, try the live demo, and download the complete source files to run the project locally.

JavaScript: Change Slides and Sync Dots
const slider = document.querySelector('.slider');
if (!slider) return;

const slides = [...slider.querySelectorAll('.slide')];
const dots = [...slider.querySelectorAll('.dot')];
const previousButton = slider.querySelector('.previous');
const nextButton = slider.querySelector('.next');
let currentIndex = 0;

function showSlide(nextIndex) {
  currentIndex = (nextIndex + slides.length) % slides.length;

  slides.forEach((slide, index) => {
    const isActive = index === currentIndex;
    slide.classList.toggle('is-active', isActive);
    slide.setAttribute('aria-hidden', String(!isActive));
  });

  dots.forEach((dot, index) => {
    const isActive = index === currentIndex;
    dot.classList.toggle('is-active', isActive);
    if (isActive) dot.setAttribute('aria-current', 'true');
    else dot.removeAttribute('aria-current');
  });
}

previousButton.addEventListener('click', () => showSlide(currentIndex - 1));
nextButton.addEventListener('click', () => showSlide(currentIndex + 1));
dots.forEach((dot, index) => {
  dot.addEventListener('click', () => showSlide(index));
});
slider.addEventListener('keydown', (event) => {
  if (event.key === 'ArrowLeft') showSlide(currentIndex - 1);
  if (event.key === 'ArrowRight') showSlide(currentIndex + 1);
});
CSS: Responsive Slide Frame
.slider {
  position: relative;
  overflow: hidden;
  border-radius: 1rem;
  aspect-ratio: 16 / 9;
}

.slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 400ms ease;
}

.slide.is-active {
  opacity: 1;
  visibility: visible;
}

.slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (prefers-reduced-motion: reduce) {
  .slide { transition: none; }
}
HTML: Accessible Slider Structure
<section class="slider" role="region" aria-roledescription="carousel" aria-label="Featured destinations" tabindex="0">
  <div class="slides" aria-live="polite">
    <article class="slide is-active" aria-hidden="false" aria-label="1 of 5">
      <img src="images/alpine-lake.svg" alt="Turquoise alpine lake below snowy mountains">
      <div class="caption">
        <h2>Alpine mornings</h2>
        <p>Still water, fresh air, room to wander.</p>
      </div>
    </article>
    <article class="slide" aria-hidden="true" aria-label="2 of 5">
      <img src="images/coast.svg" alt="Golden sunset over a calm ocean coast">
      <div class="caption">
        <h2>Coastal light</h2>
        <p>Follow the shoreline until the day slows down.</p>
      </div>
    </article>
    <!-- Add slides 3–5 with their own images and descriptions. -->
  </div>
  <button class="previous" type="button" aria-label="Show previous slide">Previous</button>
  <button class="next" type="button" aria-label="Show next slide">Next</button>
  <div class="dots" role="group" aria-label="Choose a slide">
    <button class="dot is-active" type="button" aria-label="Show slide 1" aria-current="true"></button>
    <button class="dot" type="button" aria-label="Show slide 2"></button>
  </div>
</section>