Others

Carousel

Available

Automatically rotating slides. Play/pause controls and screen reader considerations are essential.

What Is a Carousel?

A carousel is a UI component that cycles through multiple slides (banners, features, photos, etc.) in the same area. It's commonly used for hero banners on homepages and product galleries.

While convenient, carousels are prone to accessibility issues when theyauto-rotate without user control, cannot be stopped, orcannot be operated with a keyboard — making them one of the most problematic patterns.

Why Does Accessibility Matter?

Live Demo (Recommended Implementation)

The carousel below follows the APG pattern. Try operating the play/pause and previous/next controls with your keyboard.

Accessible Carousel
Early Summer Sale10% off everything

Try it: Auto-advances every 4 seconds. ⏸ to stop → ‹ › to move back and forth → Hover over or focus on the carousel to pause auto-rotation.

Tip

Adding aria-roledescription causes screen readers to announce the region as "Featured Picks, carousel" and each slide as "1 of 3, slide" (optional but improves clarity). The play/pause button label should toggle between "Stop auto-rotation" and "Start auto-rotation" to match the current state.

Keyboard Interaction

KeyActionPriority
Tab → Enter / Space (play / pause button)Toggle auto-rotation play / pauseRequired
Enter / Space (previous / next buttons)Manually move to the previous / next slide (auto-rotation stops on move)Required
Focus / HoverPause auto-rotation while focus or mouse pointer is inside the carouselRequired

Note

The play/pause button should be placed before the slides in the DOM. This lets keyboard users stop the animation as soon as they notice it.

Required WAI-ARIA Roles & Properties

TargetAttribute / RoleMeaning
Carousel containeraria-roledescription="carousel" + aria-labelConveys that this is a carousel and provides its accessible name (optional but recommended).
Play/pause button<button> + aria-label reflecting current stateAllows stopping and resuming auto-rotation (required when auto-rotation is present).
Previous/next buttons<button> + aria-labelProvides a label so the purpose is conveyed even with icon-only buttons.
Each sliderole="group" + aria-roledescription="slide" + aria-label="1 of 3"Conveys the total number of slides and the current position.
Slide containeraria-live="off | polite"Switch to off during auto-rotation and polite when stopped or manually controlled.
Hidden slideshiddenExcludes non-visible slides from screen reader output and keyboard interaction.

Implementation: Recommended Pattern (Good)

Good / Recommended

Auto-rotating carousels must include a play/pause button andpause on focus/hover. Use native <button> elements for previous/next controls, and add position labels to each slide.

Markup:

<section class="carousel"
         aria-roledescription="carousel"
         aria-label="Featured Picks">
  <!-- Play/pause button is required for auto-rotating carousels -->
  <div class="carousel-controls">
    <button type="button" aria-label="Stop auto-rotation" data-toggle>⏸</button>
    <button type="button" aria-label="Previous slide" data-prev>‹</button>
    <button type="button" aria-label="Next slide" data-next>›</button>
  </div>

  <div class="carousel-slides">
    <div role="group" aria-roledescription="slide" aria-label="1 of 3">
      …Slide 1…
    </div>
    <div role="group" aria-roledescription="slide" aria-label="2 of 3" hidden>
      …Slide 2…
    </div>
    <div role="group" aria-roledescription="slide" aria-label="3 of 3" hidden>
      …Slide 3…
    </div>
  </div>
</section>

Playback control and pause script:

let index = 0;
let playing = true;
let timer = null;

function show(i) {
  index = (i + slides.length) % slides.length;
  slides.forEach((s, n) => (s.hidden = n !== index));
}
function start() {
  playing = true;
  toggle.setAttribute('aria-label', 'Stop auto-rotation');
  // Turn off live region during rotation to prevent disruptive announcements
  slidesBox.setAttribute('aria-live', 'off');
  timer = setInterval(() => show(index + 1), 4000);
}
function stop() {
  playing = false;
  toggle.setAttribute('aria-label', 'Start auto-rotation');
  // Announce changes when stopped or manually controlled
  slidesBox.setAttribute('aria-live', 'polite');
  clearInterval(timer);
}

toggle.addEventListener('click', () => (playing ? stop() : start()));
prev.addEventListener('click', () => { stop(); show(index - 1); });
next.addEventListener('click', () => { stop(); show(index + 1); });

// Pause auto-rotation on focus/hover
carousel.addEventListener('mouseenter', () => playing && clearInterval(timer));
carousel.addEventListener('mouseleave', () => playing && start());
carousel.addEventListener('focusin', () => playing && clearInterval(timer));
carousel.addEventListener('focusout', () => playing && start());

Anti-pattern (Bad)

Below is a carousel with unstoppable auto-rotation. The arrows are <div>elements that cannot receive focus, and the slides have no position labels.

Unstoppable Auto-rotating Carousel
Feature 1

Try it: Advances every 2 seconds with no way to stop. Tab cannot focus the arrows, and screen readers cannot tell which slide is showing.

<!-- ❌ Anti-pattern -->
<div class="carousel">
  <!-- No way to stop auto-rotation, no slide labels -->
  <div class="slides">
    <div class="slide">Feature 1</div>
    <div class="slide" style="display:none">Feature 2</div>
  </div>
  <!-- div arrows cannot receive focus -->
  <div class="arrow" onclick="prev()">‹</div>
  <div class="arrow" onclick="next()">›</div>
</div>
<script>
  // Unstoppable infinite auto-rotation
  setInterval(next, 2000);
</script>

Bad / Avoid

Problems with this implementation:

  • Cannot be stopped — No play/pause button, violating WCAG 2.2.2. Unreadable for people sensitive to motion.
  • No pause on focus/hover — Slides keep switching even while the user is interacting.
  • Arrows are not focusablediv + onclick cannot be operated with a keyboard.
  • No position information — Slides lack role="group" and "X of Y" labels.

Implementation Checklist


Source (English):Carousel Pattern — W3C APG(opens in a new tab)