Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Build a horizontal image slider with a semantic list of slides, CSS scroll snapping, and JavaScript for previous/next controls and a current-slide announcement. This approach keeps the slides in a meaningful order, supports touch and keyboard navigation, and avoids automatically moving content. Add autoplay only if you can provide a clear pause control and follow the motion and focus rules below.

How the slider works

An image slider—also called a carousel or slideshow—presents a sequence of items, often one at a time. In this example, the browser scrolls a horizontal list of slides. CSS makes each slide fill the viewport and snaps the list to slide boundaries. JavaScript scrolls to the previous or next item when someone activates a button and updates a status message for assistive technology.

  • HTML provides the labelled carousel, ordered slide collection, images, captions, buttons, and status message.
  • CSS creates the horizontal layout, visual treatment, responsive sizing, and scroll snapping.
  • JavaScript handles custom controls and reports which slide is active. It is not needed merely to make a row of slides scrollable.

The example deliberately does not autoplay. User-controlled scrolling is simpler to understand and avoids moving content changing while someone reads.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build the slider

1. Add semantic HTML

Place this markup where the gallery belongs. Replace the sample image URLs, alternative text, and captions with content that accurately describes your own images. The example uses a labelled group because a carousel is not automatically important enough to be a page landmark; use a labelled region only if it merits a landmark in your page structure.

#1 Best Overall
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option
<section class="carousel" role="group" aria-roledescription="carousel" aria-labelledby="gallery-title">
  <h2 id="gallery-title">Featured places</h2>

  <div class="carousel-controls">
    <button type="button" class="previous" aria-label="Previous slide">
      Previous
    </button>
    <button type="button" class="next" aria-label="Next slide">
      Next
    </button>
  </div>

  <ul class="slides">
    <li class="slide">
      <figure>
        <img src="images/coast.jpg" alt="Rocky coastline beside blue water">
        <figcaption>The coast at midday</figcaption>
      </figure>
    </li>
    <li class="slide">
      <figure>
        <img src="images/forest.jpg" alt="Sunlight filtering between tall trees">
        <figcaption>A walk through the forest</figcaption>
      </figure>
    </li>
    <li class="slide">
      <figure>
        <img src="images/city.jpg" alt="City buildings seen at dusk">
        <figcaption>The city at dusk</figcaption>
      </figure>
    </li>
  </ul>

  <p class="slide-status" aria-live="polite" aria-atomic="true">
    Slide 1 of 3
  </p>
</section>

Use useful alternative text when an image conveys information that is not already provided nearby. If an image is purely decorative and its caption or surrounding text conveys everything relevant, use alt="". Keep the DOM order the same as the intended reading order. The slides remain in the document when offscreen; do not hide offscreen items from assistive technology in a way that makes their links or content confusing.

2. Style the scroller and snap points

Add this CSS to your stylesheet. The list scrolls horizontally, while each slide occupies one viewport-width slot. scroll-snap-type asks the browser to settle scrolling at a slide; the user can still use touch, a trackpad, or horizontal scrolling.

.carousel {
  max-width: 48rem;
  margin-inline: auto;
}

.carousel-controls {
  display: flex;
  gap: .5rem;
  justify-content: flex-end;
  margin-block: 1rem;
}

.carousel button {
  padding: .6rem .9rem;
  border: 1px solid #555;
  border-radius: .25rem;
  background: #fff;
  color: #111;
  font: inherit;
  cursor: pointer;
}

.carousel button:focus-visible {
  outline: 3px solid #1264a3;
  outline-offset: 3px;
}

.slides {
  display: flex;
  gap: 1rem;
  overflow-x: auto;
  margin: 0;
  padding: 0 0 .75rem;
  list-style: none;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
}

.slide {
  flex: 0 0 100%;
  min-width: 0;
  scroll-snap-align: center;
}

.slide figure {
  margin: 0;
}

.slide img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: .5rem;
}

.slide figcaption {
  margin-top: .5rem;
}

.slide-status {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

@media (prefers-reduced-motion: reduce) {
  .slides {
    scroll-behavior: auto;
  }
}

The visually hidden status is still available to assistive technology. Do not apply a hiding technique to the slide content itself just because it is outside the visible area. The reduced-motion rule removes smooth animated scrolling for visitors who have asked their operating system to minimize motion; the preference does not mean every visual change must be removed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. Add previous and next behavior

Put this script after the carousel markup, or load it with a deferred script. It determines the slide nearest the scroller’s left edge, scrolls one item at a time, and updates the status. The buttons wrap from the final slide to the first and vice versa, so neither control becomes an inert button at an end.

const carousel = document.querySelector('.carousel');
const scroller = carousel.querySelector('.slides');
const slides = [...scroller.querySelectorAll('.slide')];
const status = carousel.querySelector('.slide-status');
const previous = carousel.querySelector('.previous');
const next = carousel.querySelector('.next');

let activeIndex = 0;
let scrollTimer;

function updateStatus(index) {
  activeIndex = index;
  status.textContent = `Slide ${index + 1} of ${slides.length}`;
}

function goToSlide(index) {
  const nextIndex = (index + slides.length) % slides.length;
  slides[nextIndex].scrollIntoView({
    behavior: window.matchMedia('(prefers-reduced-motion: reduce)').matches
      ? 'auto'
      : 'smooth',
    block: 'nearest',
    inline: 'center'
  });
  updateStatus(nextIndex);
}

previous.addEventListener('click', () => goToSlide(activeIndex - 1));
next.addEventListener('click', () => goToSlide(activeIndex + 1));

scroller.addEventListener('scroll', () => {
  window.clearTimeout(scrollTimer);
  scrollTimer = window.setTimeout(() => {
    const scrollerCenter = scroller.getBoundingClientRect().left
      + scroller.clientWidth / 2;
    let closestIndex = 0;
    let closestDistance = Infinity;

    slides.forEach((slide, index) => {
      const rect = slide.getBoundingClientRect();
      const slideCenter = rect.left + rect.width / 2;
      const distance = Math.abs(scrollerCenter - slideCenter);
      if (distance < closestDistance) {
        closestDistance = distance;
        closestIndex = index;
      }
    });

    updateStatus(closestIndex);
  }, 100);
});

The scroll listener matters because people can change slides without the buttons, including by swiping or scrolling. It updates the announcement after scrolling settles rather than announcing every intermediate position. If you change the layout to show multiple slides at once, decide whether “current” means the slide nearest the center, the first visible slide, or a selected item, then make the status and control behavior match that definition.

Test keyboard, screen-reader, and touch behavior

Native buttons are keyboard operable without custom key handlers. Tab to each button and confirm that focus is visible; activate with Enter or Space. Also test that a user can scroll through slides with touch or another available scrolling input, and that captions and image alternatives make sense in the same order as the visual presentation.

  • Check the carousel’s accessible name and ensure the controls have meaningful names.
  • Verify the status announces a useful current position after button activation and manual scrolling.
  • Confirm offscreen slide links and content do not disappear unexpectedly from keyboard or screen-reader navigation.
  • Test with the browser and assistive technologies your audience uses. Support can vary across browser and assistive-technology combinations; an example pattern is not proof of compatibility for every setup.

Carousels can make content harder to discover. If the images are important to the page, provide another clear way to reach them, such as a gallery link or visible thumbnails, instead of relying on a visitor to infer that more slides exist.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should you add autoplay or slide pickers?

Autoplay requires explicit pause and restart behavior

For a simple gallery, leaving rotation out is usually the clearest choice. If you do add it, provide a start/stop control and put that control first in the carousel’s tab order. Stop rotation as soon as keyboard focus enters the carousel, and do not restart when focus leaves; restart only after the user explicitly requests it. Stop while the pointer hovers over carousel content as well. Users need to be able to pause movement that is too fast or distracting, and screen-reader users may lose context when content changes as they read.

For people who prefer reduced motion, start automatic rotation paused. Respect prefers-reduced-motion by reducing or removing non-essential animation, and do not use that setting as the only way to pause content: users still need an explicit control. Test autoplay with the actual browser and assistive-technology combinations relevant to your audience.

Pickers need clear selection state

Numbered slide buttons or markers can help visitors jump to a particular item. If you add them, give each a name such as “Show slide 2” and expose which one is selected, for example with an appropriate pressed or current state. Update that state when a person swipes or scrolls, not only when they click a picker. Avoid adding redundant controls that make the tab order longer without improving navigation.

CSS-native controls versus JavaScript

CSS scroll snapping already provides a straightforward way to paginate a scroller. MDN also documents evolving CSS carousel features, including ::scroll-button(), ::scroll-marker-group, and ::scroll-marker, which can create browser-managed scroll buttons and markers. These features may reduce custom scripting, but support is evolving and the cited guidance does not establish a complete browser-support matrix. Check current support for the browsers and devices your site must serve before relying on them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Approach Useful when Trade-off
Scrollable list with scroll snapping You want touch and scroll navigation with minimal behavior code. It does not by itself provide custom slide status or app-specific control state.
JavaScript buttons and status You need named controls, explicit slide changes, announcements, or picker state. You must keep state synchronized with manual scrolling and test keyboard and assistive-technology behavior.
CSS-native carousel controls Your target browsers support the relevant features and browser-managed controls fit your design. Feature availability is evolving; verify the intended browser set rather than assuming universal support.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting

The slides appear vertically

Check that the list has display: flex and that each slide has a fixed flex basis such as flex: 0 0 100%. Also check for other stylesheet rules overriding either declaration.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

The slider moves but does not settle on a slide

Confirm that the scrolling element has scroll-snap-type: x mandatory and each slide has scroll-snap-align. Snap alignment belongs on the child items; the snap type belongs on the scrolling container.

The buttons do nothing

Check the browser console for a selector error and make sure the script runs after the carousel markup exists. Confirm the class names in the HTML match the selectors in the script and that there is at least one slide.

The status is wrong after a swipe

Make sure the scroll listener is attached to the element that actually scrolls, not an outer wrapper. If your design shows partial slides, change the active-slide rule to reflect what “current” means in that layout.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Images are cropped or stretched

object-fit: cover fills the frame by cropping edges when the source image has a different aspect ratio. Use object-fit: contain if showing the complete image matters more than filling the frame, and set an appropriate background color for any remaining space.

Performance and reliability

Use appropriately sized image files so the browser does not download unnecessarily large assets for a small display. Keep the number of initially loaded images reasonable on pages with large galleries; if you add lazy loading, test that the next slide is ready when reached, especially on slower connections. Avoid tying essential navigation to animation completion events: reduced-motion settings or interrupted scrolling should not leave controls stuck in a transitional state.

Test at narrow and wide viewport sizes, with keyboard-only navigation, with reduced motion enabled, and with touch input. The example uses browser scrolling rather than maintaining complex animation state, but its announcement and active-index logic still need to match any changes you make to slide width, spacing, or visible-slide count.

Or skip the browser setup

If the goal is to capture a screenshot of a page containing your slider, rather than build the slider itself, ScreenshotNeo is a website screenshot API and MCP server for developers. One GET request returns an image or PDF. For example, using the supplied API pattern with the slider page URL:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/gallery -o shot.webp

See the ScreenshotNeo documentation for request options. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The Free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up free for ScreenshotNeo.

Frequently Asked Questions

Is an image slider the same thing as a carousel?

Usually, yes. “Carousel,” “slideshow,” and “slider” are commonly used for a sequence of items presented one at a time or in a scrolling collection.

Do I need JavaScript to make slides scroll horizontally?

No. A horizontally overflowing flex list with CSS scroll snapping can scroll without JavaScript. JavaScript is for custom state and behaviors such as slide buttons and announcements.

Quick Recap

SaleBestseller No. 1
HTML and CSS: Design and Build Websites
HTML and CSS: Design and Build Websites
HTML CSS Design and Build Web Sites; Comes with secure packaging; It can be a gift option
$15.73
SaleBestseller No. 3
SaleBestseller No. 4
Web Design with HTML, CSS, JavaScript and jQuery Set
Web Design with HTML, CSS, JavaScript and jQuery Set
Brand: Wiley; Set of 2 Volumes
$35.05

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.