The Easiest Accessible Swiper.JS Carousel Solution to Date

Share this post

Swiper JS plus real accessibility rated E for every one

At Graceful Web Studio, we’ve implemented Swiper JS carousels on dozens of websites. Nearly every client—especially those in mission-driven or regulated industries—has asked for a carousel that’s not only interactive and space-saving, but also WCAG-conformant and accessible to keyboard and screen reader users.

Each time, we’ve learned more. And now, with our latest implementation for Walden Mutual Bank, we’ve arrived at what we believe is the simplest, most reliable, and reusable approach to making Swiper JS accessible.

This post details our updated method, explains why we’ve moved beyond Swiper’s built-in accessibility tools, and shows you how to implement an accessible carousel—fast.

Why Swiper JS Accessibility Falls Short

Swiper JS includes a module called a11y which claims to:

  • Add role="region" and aria-label to the carousel container
  • Inject a live region with .swiper-notification
  • Provide accessible name, role, and value for container and slides
  • Announce slide changes via a live region (though inconsistently in practice)

Note: Even when the a11y module is disabled, Swiper JS still automatically adds:

  • role="group" and aria-label="Slide X of Y" to each .swiper-slide
  • aria-current="true" to the active pagination bullet
  • an aria-live="polite" attribute to the container .swiper-wrapper element
  • correct names are applied to slider dot buttons "Slide 1" "Slide 2" etc.

This means you don’t need to manually add these ARIA attributes.

However, in practice, here’s what we’ve found:

  • The live region is not injected with text to announce anything meaningful
  • Slides remain in the DOM and are never hidden from assistive technologies therefore nothing hidden + nothing revealed = nothing announced in live region
  • aria-live is applied to the element (.swiper-wrapper) but again useless with nothing hidden/revealed inside of it
  • You must customize what gets announced and when

For financial institutions and purpose-driven organizations that need to meet WCAG conformance—not just suggest effort—these gaps are unacceptable.

What We Needed Instead

By adding keyboard: { enabled: true } and pagination: { clickable: true } to our Swiper configuration, we ensured that all navigation controls—including the previous/next arrows and pagination bullets—are fully keyboard accessible. These two options are critical for enabling users to move through the carousel using Tab, Enter, or Spacebar, especially when bypassing the built-in a11y module.

For our client, Walden Mutual Bank, we required:

  • A named and labeled region (role="region", aria-label) for screen reader context
  • Clear, consistent announcements of dynamic slide changes
  • Reliable keyboard access to all controls (prev/next, pagination bullets)
  • Control over when and what is announced in the live region
  • A solution that works in Webflow

Our Final Swiper JS Setup (Webflow-Friendly)

We used Swiper’s core for structure and motion—but completely disregarded its a11y module. Instead, we used there once useless live region (.swiper-notification) for announcements and handled some of the ARIA roles and labels ourselves.

âś… HTML Setup

<div class="swiper for-individuals" role="region" aria-label="Tailored solutions for individuals">  
  <div class="swiper-wrapper">    
    <div class="swiper-slide"> ... </div>    
    <div class="swiper-slide"> ... </div>    
    <div class="swiper-slide"> ... </div>  
  </div>  
  <div class="swiper-pagination"></div>  
  <div class="swiper-button-prev" aria-label="Previous Slide"></div>  
  <div class="swiper-button-next" aria-label="Next Slide"></div>
</div>

âś… Styles

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />

<style>
:root {  
  --swiper-navigation-size: 28px;
}
.swiper-button-next,.swiper-button-prev {  
  top: 35% !important;  
  width: 30px !important;  
  height: 30px !important;  
  color: #000;
}
.swiper-pagination-bullet {  
  width: 24px;  height: 24px;  
  background-color: #777;  
  opacity: 1;
}
.swiper-pagination-bullet-active {  
	background-color: #000;
}
.swiper-pagination-bullet:focus-visible {  
  outline: -webkit-focus-ring-color auto 1px;  
  outline-offset: 3px;
}
</style>

âś… JavaScript (Drop this in page settings before closing </body> tag

<!-- Swiper CDN -->
<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>

<!-- Graceful Web Studio Custom -->
<script>
const swiper = new Swiper('.for-individuals', {
  loop: true,
  navigation: {
    nextEl: '.swiper-button-next',
    prevEl: '.swiper-button-prev',
  },
  pagination: {
    el: '.swiper-pagination',
    clickable: true,
  },
  keyboard: {
    enabled: true,
    onlyInViewport: true,
  }
});

// Accessibility announcements

document.addEventListener('DOMContentLoaded', () => {
  const wrapper = document.querySelector('.for-individuals .swiper-wrapper');
  const liveRegion = document.querySelector('.for-individuals .swiper-notification');

  if (wrapper?.hasAttribute('aria-live')) {
    wrapper.removeAttribute('aria-live');
  }

  const announce = (message) => {
    if (liveRegion) {
      liveRegion.textContent = message;
      setTimeout(() => {
        liveRegion.textContent = '';
      }, 1000);
    }
  };

  document.querySelectorAll('.swiper-pagination-bullet').forEach((btn) => {
    btn.addEventListener('click', () => announce('Showing selected slide'));
    btn.addEventListener('keydown', (e) => {
      if (e.key === 'Enter' || e.key === ' ') {
        announce('Showing selected slide');
      }
    });
  });

  document.querySelector('.swiper-button-next')?.addEventListener('click', () => announce('Showing next slide'));
  document.querySelector('.swiper-button-prev')?.addEventListener('click', () => announce('Showing previous slide'));
});
</script>

Why This Matters

Every website we’ve built recently has asked for some form of accessible carousel. These components are in high demand, and developers are looking for fast, effective ways to implement them without sacrificing usability.

Our goal is to help teams:

  • Save time
  • Maintain control
  • Deliver a better experience for everyone
  • Acheive WCAG conformance

If you're building carousels and frustrated with the state of accessibility in libraries like Swiper JS, know this: you are not alone—and you don't have to compromise.

This pattern has been refined with every use, and continues to meet both design and accessibility goals without excess code or confusion.

Want to Build One?

You can copy the setup above and drop it right into your Webflow project, or reach out to us for a ready-made accessible Swiper component.

Check out Swiper.js demos for more excting styles.

👉 Read our first post: Why I Chose Swiper JS for My Webflow Carousel and How I Made It Accessible

đź“© Have questions? DM us or share your feedback on LinkedIn.

Let’s build a more accessible web—one carousel at a time.

Your Website Deserves Better, Let's Team Up

Send a message or request a project quote for an estimate within 24 hours. Prefer to chat? Book a call, and let’s find the right solution for you!