Creating an Accessible Swiper Slider with Custom Play/Pause Button and Enhanced Accessibility Features

In today’s digital landscape, ensuring that web content is accessible to all users, including those with disabilities, is paramount. Sliders are a popular web design element, but they often fall short when it comes to accessibility. In this guide, we’ll walk you through the steps to create an accessible Swiper slider, complete with a custom play/pause button and tailored accessibility enhancements. By the end of this tutorial, you’ll be equipped with the knowledge to deliver a seamless and inclusive user experience for everyone visiting your website. Let’s dive in!

1. HTML Structure

First, let’s set up the HTML structure for our Swiper slider:

<div id="slider-id" class="swiper dsb-slider">
    <div class="swiper-wrapper">
        <!-- Swiper Slide 1 -->
        <div class="swiper-slide">
            <img src="path_to_image1.jpg" alt="Description for Image 1">
            <div class="carousel-caption">
                <p class="lead">Caption for Image 1</p>
            </div>
            <div class="slide-caption">
                <h2 class="heading" tabindex="0">Heading for Slide 1</h2>
                <p class="lead">Description for Slide 1</p>
                <a class="button" href="#">Button Text</a>
            </div>
        </div>
        <!-- Add more slides as needed -->
    </div>
    <div class="swiper-pagination"></div>
    <button class="dsb-button-control" aria-pressed="false">
        <span class="screen-reader-text">Pause</span>
        <span class="dashicons dashicons-controls-pause"></span>
    </button>
</div>

2. JavaScript Implementation

Now, let’s move on to the JavaScript part:

2.1 Swiper Configuration

First, we’ll define the Swiper configuration:

let args = {
    loop: true,
    speed: 1000,
    autoplay: {
        delay: 5000,
    },
    pagination: {
        el: '.swiper-pagination',
        clickable: true,
    },
    on: {
        afterInit: function (dsb_slider) {
            // Accessibility functions will be added here
        },
    }
};

2.2 Accessibility Enhancements

Inside the afterInit function, we’ll add our accessibility enhancements:

on: {
    afterInit: function (dsb_slider) {
        // Jump to the current active bullet on tab
        const button = document.querySelectorAll('.button');
        button.forEach(function (item) {
            item.addEventListener('keydown', function (event) {
                if (event.keyCode === 9) {
                    event.preventDefault();
                    const activeBullet = document.querySelector('.swiper-pagination-bullet-active');
                    activeBullet.focus();
                }
            });
        });

        // Space key to click pagination bullet and focus on h2 when clicked
        const pagination = document.querySelectorAll('.swiper-pagination-bullet');
        pagination.forEach(function (item, index) {
            item.addEventListener('keydown', function (event) {
                if (event.keyCode === 32) {
                    event.preventDefault();
                    item.click();
                }
            });
            item.addEventListener('click', function() {
                const h2Element = dsb_slider.slides[index].querySelector('h2');
                if (h2Element) {
                    h2Element.focus();
                }
            });
        });

        // Play/Pause control button
        const controlBtn = document.querySelector('.dsb-button-control');
        controlBtn.addEventListener('click', function () {
            if (this.getAttribute('aria-pressed') === 'false') {
                dsb_slider.autoplay.stop();
                this.querySelector('.screen-reader-text').textContent = 'Play';
                this.querySelector('.dashicons').classList.remove('dashicons-controls-pause');
                this.querySelector('.dashicons').classList.add('dashicons-controls-play');
                this.setAttribute('aria-pressed', 'true');
            } else {
                dsb_slider.autoplay.start();
                this.querySelector('.screen-reader-text').textContent = 'Pause';
                this.querySelector('.dashicons').classList.remove('dashicons-controls-play');
                this.querySelector('.dashicons').classList.add('dashicons-controls-pause');
                this.setAttribute('aria-pressed', 'false');
            }
        });
    },
}

2.3 Initialize Swiper

Finally, we’ll initialize the Swiper slider:

const dsb_slider = new Swiper('#slider-id', args);

Full code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Accessible Swiper Slider with Custom Play/Pause & Enhancements</title>
    <link rel="stylesheet" href="https://unpkg.com/swiper/swiper-bundle.min.css">
    <style>
    :root {
        --swiper-pagination-bullet-horizontal-gap: 5px;
    }

    .dsb-slider .slide-caption {
        background-color: rgba(255,255,255,.95);
        padding: 2em;
        text-align: left;
        overflow: visible;
        left: 0%;
        right: 0%;
        text-shadow: none;
        bottom: 0;
        top: unset;
        position: absolute;
        width: 33%;
    }
    .dsb-slider .swiper-pagination {
        position: absolute;
        left: 29%;
        z-index: 15;
        width: 60%;
        padding-left: 0;
        margin-left: -30%;
        text-align: center;
        list-style: none;
        bottom: 10px;
        top: unset;
    }
    .dsb-slider .swiper-pagination-bullet.dsb-pagination-bullet-active {
        background-color: black;
    }
    .dsb-slider .swiper-pagination-bullet {
        background-color: #747474;
        opacity: 1;
    }
    .dsb-slider .swiper-pagination-bullet:focus {
        outline: 1px solid black;
        outline-offset: 2px;
    }
    .dsb-slider .button {
        background-color: #FF6200;
        color: black !important;
        border: none;
        text-decoration: none;
        padding: .5em 1em;
        font-size: 1em;
        border-radius: 25px;
    }
    .dsb-slider .button:hover {
        background-color: #193662;
        color: white !important;
    }
    .dsb-slider .button:focus {
        outline: 2px solid #193662;
        outline-offset: 2px;
    }
    .dsb-slider .dsb-button-control{
        background-color: #FF6200;
        color: #fff !important;
        border: none;
        text-decoration: none;
        padding: .5em;
        position: absolute;
        right: 2em;
        bottom: 2em;
        z-index: 15;
        cursor: pointer;
    }
    .dsb-slider .dsb-button-control:hover {
        background-color: #193662;
        color: white !important;
    }
    .dsb-slider .dsb-button-control:focus {
        outline: 2px solid white;
        outline-offset: 2px;
    }
    .dsb-slider h2.heading:focus {
        outline: 0;
    }
    /* mobile */
    @media (max-width: 767px) {

        .dsb-slider h2.heading {
            font-size: 1em;
            line-height: 1.2em;
            padding-bottom: 5px;
        }
        .dsb-slider .lead {
            font-size: .8em;
            line-height: 1em;
            margin-bottom: 1em;
            max-width: 80%;
        }
        .dsb-slider .slide-caption {
            position: relative;
            width: 100%;
            padding: 1em 1em 2em;
        }
        .dsb-slider .button {
            padding: .3em .5em;
            font-size: .8em;
        }
        .dsb-slider .swiper-pagination {
            left: 0;
            bottom: 0;
            text-align: left;
            margin-left:0;
            padding-left: 1em;
        }
        .dsb-slider .dsb-button-control{
            right: 1em;
            bottom: 1em;
        }
        .dsb-slider .dsb-button-control:focus {
            outline: 2px solid #193662;
            outline-offset: 2px;
        }
    }

    </style>
</head>
<body>

<div id="slider-id" class="swiper dsb-slider">
    <div class="swiper-wrapper">
        <!-- Swiper Slide 1 -->
        <div class="swiper-slide">
            <img src="https://via.placeholder.com/500x300?text=Slide+1" alt="Description for Image 1">
            <div class="carousel-caption">
                <p class="lead">Caption for Image 1</p>
            </div>
            <div class="slide-caption">
                <h2 class="heading" tabindex="0">Heading for Slide 1</h2>
                <p class="lead">Description for Slide 1</p>
                <a class="button" href="#">Button Text</a>
            </div>
        </div>
        <!-- Swiper Slide 2 -->
        <div class="swiper-slide">
            <img src="https://via.placeholder.com/500x300?text=Slide+2" alt="Description for Image 2">
            <div class="carousel-caption">
                <p class="lead">Caption for Image 2</p>
            </div>
            <div class="slide-caption">
                <h2 class="heading" tabindex="0">Heading for Slide 2</h2>
                <p class="lead">Description for Slide 2</p>
                <a class="button" href="#">Button Text</a>
            </div>
        </div>
    </div>
    <div class="swiper-pagination"></div>
    <button class="dsb-button-control" aria-pressed="false">
        <span class="screen-reader-text">Pause</span>
        <span class="dashicons dashicons-controls-pause"></span>
    </button>
</div>

<!-- Include Swiper's JS and jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>
<script>
    let args = {
        loop: true,
        speed: 1000,
        autoplay: {
            delay: 5000,
        },
        pagination: {
            el: '.swiper-pagination',
            clickable: true,
        },
        on: {
            afterInit: function (dsb_slider) {
            // Jump to the current active bullet on tab
            const button = document.querySelectorAll('#slider-id .button');
            button.forEach(function (item) {
                item.addEventListener('keydown', function (event) {
                    if (event.keyCode === 9) {
                        event.preventDefault();
                        const activeBullet = document.querySelector('.swiper-pagination-bullet-active');
                        activeBullet.focus();
                    }
                });
            });

            // Space key to click pagination bullet and focus on h2 when clicked
            const pagination = document.querySelectorAll('#slider-id .swiper-pagination-bullet');
            pagination.forEach(function (item, index) {
                item.addEventListener('keydown', function (event) {
                    if (event.keyCode === 32) {
                        event.preventDefault();
                        item.click();
                    }
                });
                item.addEventListener('click', function() {
                    const h2Element = dsb_slider.slides[index].querySelector('h2');
                    if (h2Element) {
                        h2Element.focus();
                    }
                });
            });

            // Play/Pause control button
            const controlBtn = document.querySelector('#slider-id .dsb-button-control');
            controlBtn.addEventListener('click', function () {
                if (this.getAttribute('aria-pressed') === 'false') {
                    dsb_slider.autoplay.stop();
                    this.querySelector('.screen-reader-text').textContent = 'Play';
                    this.querySelector('.dashicons').classList.remove('dashicons-controls-pause');
                    this.querySelector('.dashicons').classList.add('dashicons-controls-play');
                    this.setAttribute('aria-pressed', 'true');
                } else {
                    dsb_slider.autoplay.start();
                    this.querySelector('.screen-reader-text').textContent = 'Pause';
                    this.querySelector('.dashicons').classList.remove('dashicons-controls-play');
                    this.querySelector('.dashicons').classList.add('dashicons-controls-pause');
                    this.setAttribute('aria-pressed', 'false');
                }
            });
        },
        }
    };

    (function($){
        var initializeBlock = function() {
            const dsb_slider = new Swiper('#slider-id', args);
        }

        $(document).ready(function(){
            initializeBlock();
        });
    })(jQuery);
</script>

</body>
</html>

The above code snippet demonstrates several key points of accessibility implemented in a Swiper configuration. Here’s an overview:

  1. Keyboard Navigation with Focus Management:
    • The code uses an event listener for the ‘Tab’ key (keyCode 9) to ensure that when users navigate using the keyboard, the focus jumps to the currently active bullet in the Swiper pagination, improving keyboard-based navigation.
  2. Space Key to Click Pagination Bullets:
    • An event listener for the ‘Space’ key (keyCode 32) allows users to interact with Swiper pagination bullets by simulating a click when the ‘Space’ key is pressed. This provides an accessible way for keyboard-only users to navigate through Swiper slides.
  3. Focus Management on Click:
    • When a pagination bullet is clicked, the code ensures that the corresponding h2 element within the respective slide gains focus. This guides users using assistive technologies or keyboard-only navigation to the most relevant content in the slide.
  4. Accessible Play/Pause Control with Aria Attributes:
    • The code implements a Play/Pause control button for Swiper autoplay with proper ARIA attributes (aria-pressed) to indicate the state of the button to assistive technologies.
    • The text content for screen readers and the icon for visual users change depending on whether autoplay is active or paused, providing clear feedback on the button’s function.

These accessibility features help make the Swiper more user-friendly for a broader audience, particularly for those relying on keyboard navigation or assistive technologies.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top