accessible-slick

the last (accessible) carousel you'll ever need

View source on Github

accessible-slick

Read more about why this package exists and what makes it accessible over on the project's Github repo!

A highly accessible, WCAG 2.0 / 2.1 compliant, drop-in replacement for Slick Slider (1.8.1) crafted and tested by expert users and professional accessibility consultants, intended to make life easier for real-world dev teams who need to pass accessibility audits.

Features

All of the same great features as the original Slick package, along with:

  • The wrapper now has a role="region" and a clear, configurable aria-label.
  • Each slide has role="group" with a numbered aria-label.
  • Autoplay now automatically comes with a pause/play toggle button.
  • No more tab markup! Just simple, semantic elements like lists and buttons.
  • The accessibility setting has been deprecated since this package is accessible by default!
  • Keyboard navigation has been removed so that screen reader users don't have to fight their virtual cursor!
  • The Previous and Next buttons now use clean, semantic markup. Say goodbye to those aria-labels!
  • Screen-reader-only instructions can now be added to explain complex behaviors to screen reader users.
  • A new, more accessible theme is now available (accessible-slick-theme.min.css), which comes with bigger icons and better, browser-default focus indicators! It's used by all the demos below.
  • When centerMode is enabled, the centered slide will be indicated with the text " (centered)" at the end of its aria-label.

Read more about all of these features here!

Demos

Single Item

1

2

3

4

5

6

$('.single-item').slick();

Multiple Items

1

2

3

4

5

6

7

8

9

$('.multiple-items').slick({
  infinite: true,
  slidesToShow: 3,
  slidesToScroll: 3
});

Responsive Display

1

2

3

4

5

6

7

8

$('.responsive').slick({
  dots: true,
  infinite: false,
  speed: 300,
  slidesToShow: 4,
  slidesToScroll: 4,
  responsive: [
    {
      breakpoint: 1024,
      settings: {
        slidesToShow: 3,
        slidesToScroll: 3,
        infinite: true,
        dots: true
      }
    },
    {
      breakpoint: 600,
      settings: {
        slidesToShow: 2,
        slidesToScroll: 2
      }
    },
    {
      breakpoint: 480,
      settings: {
        slidesToShow: 1,
        slidesToScroll: 1
      }
    }
    // You can unslick at a given breakpoint now by adding:
    // settings: "unslick"
    // instead of a settings object
  ]
});

TIP: Don't remove controls in smaller viewports!

Never disable both the previous/next buttons and the slide dots! Some people use screen readers (like VoiceOver and TalkBack), while others can't do gestures. Be sure to give them at least one set of controls they can use.

Variable Width

200

175

150

300

225

125

$('.variable-width').slick({
  dots: true,
  infinite: true,
  speed: 300,
  slidesToShow: 1,
  centerMode: true,
  variableWidth: true
});

NOTE: starting in Slick v1.8.1, variable slide widths cannot be defined directly on individual slides using the style attribute as shown in the original demo. Instead, set the width of the inner content, like so (or via external CSS):

<div class="slider variable-width">
  <div>
    <p style="width: 200px;">200</p>
  </div>
  ..
</div>

Adaptive Height

1

2

Look ma!

3

Check
this out!

4

Woo!

$('.adaptive-height').slick({
  dots: true,
  infinite: true,
  speed: 300,
  slidesToShow: 1,
  adaptiveHeight: true
});

Data Attribute Settings

In slick 1.5+ you can now add settings using the data-slick attribute. You still need to call $(element).slick() to initialize slick on the element.

1

2

3

4

5

6

<div data-slick='{"slidesToShow": 4, "slidesToScroll": 4}'>
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
</div>

Center Mode

1

2

3

4

5

6

$('.center').slick({
  centerMode: true,
  centerPadding: '60px',
  slidesToShow: 3,
  responsive: [
    {
      breakpoint: 768,
      settings: {
        arrows: false,
        dots: true,
        centerMode: true,
        centerPadding: '40px',
        slidesToShow: 3
      }
    },
    {
      breakpoint: 480,
      settings: {
        arrows: false,
        dots: true,
        centerMode: true,
        centerPadding: '40px',
        slidesToShow: 1
      }
    }
  ]
});

Lazy Loading

Fonz and Richie standing in front of motorcycle.
Close headshot of Fonz.
Fonz sitting on motorcycle, looking over his shoulder at the camera.
Fonz in jumpsuit looking to the left, talking to a shorter character with dark hair.
Fonz and Richie sitting at a diner table, with Fonz explaining something.
Fonz posing on the side of a motorcycle, with one hand and one foot on the bike. Other hand in jacket, other leg on the ground.
// To use lazy loading, set a data-lazy attribute
// on your img tags and leave off the src. Don't
// forget that alt description!

<img data-lazy="img/lazyfonz1.png" alt="[image description here]">

$('.lazy').slick({
  lazyLoad: 'ondemand',
  slidesToShow: 3,
  slidesToScroll: 1
});

TIP: don't forget those image descriptions!

If your slides contain nothing but images, those images almost certainly need alt descriptions in order to fulfill WCAG 1.1.1.

Autoplay

1

2

3

4

5

6

$('.autoplay').slick({
  slidesToShow: 3,
  slidesToScroll: 1,
  autoplay: true,
  autoplaySpeed: 2000,
});

In accessible-slick, a pause/play icon button is automatically added when autoplay is enabled in order to comply with WCAG 2.2.2.

TIP: don't remove the pause button!

DO NOT disable the autoplay pause/play button unless you are replacing it with a reasonable alternative mechanism for pausing, stopping, or hiding the carousel (WCAG 2.2.2).

If you know what you are doing, set useAutoplayToggleButton to false to get rid of the button.

Fade

Fonz getting pulled behind a boat on water skis on a lake, wearing a leather jacket, for some reason.
Fonz dancing next to Richie while Richie sits smiling on a motorcycle.
Fonz sitting on a motorcycle, looking up a talking to three men standing around him.
$('.fade').slick({
  dots: true,
  infinite: true,
  speed: 500,
  fade: true,
  cssEase: 'linear'
});

TIP: don't forget those image descriptions!

If your slides contain nothing but images, those images almost certainly need alt descriptions in order to fulfill WCAG 1.1.1.

Add & Remove

1

$('.add-remove').slick({
  slidesToShow: 3,
  slidesToScroll: 3
});

$('.js-add-slide').on('click', function() {
  slideIndex++;
  $('.add-remove').slick('slickAdd','
' + slideIndex + '
'); }); $('.js-remove-slide').on('click', function() { $('.add-remove').slick('slickRemove',slideIndex - 1); if (slideIndex !== 0){ slideIndex--; } });

Filtering

1

2

3

4

5

6

7

8

9

10

11

12

$('.filtering').slick({
  slidesToShow: 4,
  slidesToScroll: 4
});

var filtered = false;

$('.js-filter').on('click', function(){
  if (filtered === false) {
    $('.filtering').slick('slickFilter',':even');
    $(this).text('Unfilter Slides');
    filtered = true;
  } else {
    $('.filtering').slick('slickUnfilter');
    $(this).text('Filter Slides');
    filtered = false;
  }
});

Destroy

If you really want to be that guy...

$('.your-slider').slick('unslick');

Slider Syncing

1

2

3

4

5

1

2

3

4

5

 $('.slider-for').slick({
  slidesToShow: 1,
  slidesToScroll: 1,
  arrows: false,
  fade: true,
  asNavFor: '.slider-nav',
  instructionsText: 'Changing this current slide of this carousel will change the current slide of the thumbnail carousel that follows.',
  regionLabel: 'main image carousel'
});

$('.slider-nav').slick({
  slidesToShow: 3,
  slidesToScroll: 1,
  asNavFor: '.slider-for',
  dots: true,
  centerMode: true,
  instructionsText: 'Changing the current slide of this carousel will change the current slide of the preceding main image carousel.',
  regionLabel: 'thumbnail carousel'
});

TIP: always explain how sliders are synced!

Use the new instructionsText setting to provide clear, simple instructions for screen reader users to explain what happens when they interact with these sliders. These instructions will be added as screen-reader-only text at the beginning of the slider.

TIP: differentiate adjacent carousels

Use the new regionLabel setting to change to aria-label on the wrapper regions so that they are easier for screen reader users to tell apart. Even better, use that same text in the instructions you provide so these users know what to listen for as they explore the page!

Right to Left

1

2

3

4

5

6

$('.single-item-rtl').slick({
  rtl: true
});

Note: the HTML tag of the slider, or the parent element of the slider, must have the attribute dir="rtl".

and a whole lot more...

Getting Started

Set up your HTML markup.

<div class="your-class">
  <div>your content</div>
  <div>your content</div>
  <div>your content</div>
</div>

Move the /slick folder into your project

Add slick.min.css and one of the theme files in your <head>

<-- Option #1 (original theme) -->
<link rel="stylesheet" type="text/css" href="slick/slick-theme.min.css">

<-- Option #2 (accessible theme) -->
<link rel="stylesheet" type="text/css" href="slick/accessible-slick-theme.min.css">

Add slick.min.js before your closing <body> tag, after jQuery (requires jQuery 1.7+)

<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="slick/slick.min.js"></script>

Initialize your slider in your script file or an inline script tag

$(document).ready(function() {
  $('.your-class').slick({
    setting-name: setting-value
  });
});

When complete, your HTML should look something like:

<html>
  <head>
    <title>My Now Amazing Webpage</title>
    <link rel="stylesheet" type="text/css" href="slick/slick.css">
    <link rel="stylesheet" type="text/css" href="slick/accessible-slick-theme.css">
  </head>

  <body>
    <div class="your-class">
      <div>your content</div>
      <div>your content</div>
      <div>your content</div>
    </div>

    <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script type="text/javascript" src="slick/slick.min.js"></script>

    <script type="text/javascript">
      $(document).ready(function() {
        $('.your-class').slick({
          setting-name: setting-value
        });
      });
    </script>
  </body>
</html>

Settings

With just a few important exceptions, all of the original settings are still available. Additionally, the following new settings are also now available:

Setting Type Default Description
arrowsPlacement string ('beforeSlides' | 'afterSlides' | 'split') null Determines where the previous and next arrows are placed in the slider DOM, which determines their tabbing order. Arrows can be placed together before the slides or after the slides, or split so that the previous arrow is before the slides and the next arrow is after (this is the default). Use this setting to ensure the tabbing order is logical based on your visual design to fulfill WCAG 1.3.2 and 2.4.3
instructionsText string null Instructions for screen reader users placed at the very beginning of the slider markup. If you are using asNavFor or adding custom functionality with API methods/events, you probably need to supply instructions!
pauseIcon string (html | jQuery selector) | object (DOM node | jQuery object) <span class="slick-pause-icon" aria-hidden="true"></span> Custom element to use as the "pause" icon inside the autoplay pause/play toggle button, when autoplay is enabled.
playIcon string (html | jQuery selector) | object (DOM node | jQuery object) <span class="slick-play-icon" aria-hidden="true"></span> Custom element to use as the "play" icon inside the autoplay pause/play toggle button, when autoplay is enabled.
regionLabel string 'carousel' Text to use for the aria-label that is placed on the wrapper.
useAutoplayToggleButton boolean true Controls whether a pause/play icon button is added when autoplay is enabled. Setting this to false without providing an alternative control would likely violate WCAG 2.2.2, so be careful!
useGroupRole boolean true Controls whether role="group" and an aria-label are applied to each slide.

NOTE: deprecated settings

The accessibility, focusOnChange, and focusOnSelect settings no longer do anything, but nothing will break if they are passed in by a legacy config. Read more about these changes here.

Events

All of the original events are available.

Methods

All of the original methods are available.

Go Get It

Download Now View On Github

You can also use accessible-slick with the jsDelivr CDN!

CSS
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/@accessible360/accessible-slick@1.0.1/slick/slick.min.css">

Theme CSS option #1 (original)
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/@accessible360/accessible-slick@1.0.1/slick/slick-theme.min.css">

Theme CSS option #2 (accessible)
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/@accessible360/accessible-slick@1.0.1/slick/accessible-slick-theme.min.css">

JS
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/@accessible360/accessible-slick@1.0.1/slick/slick.min.js"></script>