About Version 4

Splide v4

I never expected current exponential growth of my library when I created it, but now Splide has over 300 million hits/month on jsDelivr✨. Surprisingly, it's more than the number of Swiper that is the one of the most popular carousel libraries. I know it's not the only way to distribute a package, but I'd like to thank all Splide users, and much appreciate all sponsors!

Now new version has come, improving accessibility and usability. Here is the summary of v4 updates:

  • Revise accessibility with following W3C Carousel Design Pattern
  • Install a Live Region for screen reader users
  • Reduce non-essential motions when detecting the prefers-reduced-motion media feature
  • Support a toggle (combined play-pause) button for autoplay
  • Make breakpoints behave like CSS media query, ensuring the same carousel between window resize and page load
  • Implement the Drag Free Snap mode
  • Make the direction option responsive
  • Add options to control the wheel sensitivity for inertia scroll
  • Patch :focus-visible for IE and Safari, and add focus styles to themes
  • Some bug fixes

A bad new: code size increased (27Kb→29Kb).

Breaking Changes

If these changes may affect your carousel, modify your code by following Migrating from v3 to v4.

  • Change default behaviour of keyboard, waitForTransition and slideFocus
  • Drop support for separated play/pause buttons for autoplay, and support a toggle button (combined play-pause) instead
  • Drop support for splide__slider element, removing arrows: 'slider' and pagination: 'slider' options
  • Change some methods in Components

Also, update following items for new features:

If you are using React, Vue or Svelte Splide, follow each instruction:

New Features

Robust Accessibility

To make Splide accessibility robuster and more reliable, I've revised roles and attributes so that the carousel complies with W3C Carousel Design Pattern, and installed a Live Region that is very helpful for screen reader users.

With a live region, screen readers are able to announce contents of the newly visible slide every time when a carousel moves. You can see how NVDA which is a famous screen reader reads contents in this video:

Additionally, I've implemented "reduced motion" mode that automatically disables transition effects while prefers-reduced-motion media feature is reduced for those who experience distraction or nausea from animation (WCAG 2.3.3).

If you are interested in these accessibility improvements, see this long document.


Old Splide updated current options by options associated with matched breakpoint, hence you might get different result between window resize and page refresh. For example, think you have these options with breakpoints:

perPage : 3,
gap : '1rem',
breakpoints: {
1200: { perPage: 2, gap: '1rem' },
640 : { gap: 0 },

When you open the page on a desktop (> 1200px), the carousel has 3 slides in a view. And then, if you resize down the window to 640px or below, the carousel will have 2 slides because the window passes through 1200: { perPage: 2 }. On the other hand, when you open the page on a mobile (≤ 640px), the carousel has 3 slides instead of 2.

To get the desired result, you had to add all options that you want to update into both base and breakpoints:

perPage : 3,
gap : '1rem',
breakpoints: {
1200: { perPage: 2, gap: '1rem' },
640 : { perPage: 2, gap: 0 },

In v4, I've made breakpoints behave as like media queries because:

  • Some people were confused by the difference with CSS
  • It can ensure the same result between window resize and page refresh
  • It is more understandable what options will be used on the specific point

By this change, Splide merges all options in breakpoints that matches the current width into base options. For example, when you open the page with following options on a mobile(≤ 640px):

arrows : true,
perPage: 3,
breakpoints: {
1200: { arrows: false },
800 : { perPage: 2 },
640 : {},

...your carousel has 2 slides and no arrows since 1200 and 800 also match the device width.

Besides, values will be reset to default if base options do not contain their keys. For example, if you specify the width of slides on a specific breakpoint:

breakpoints: {
1200: { fixedWidth: 200 },

...the width will be reset to the default value (undefined) when you widen the window over 1200px.

Although this change won't break your breakpoints since you defined them in the stricter way than the new one, I recommend checking your carousel just in case.

Migrating from v3 to v4


Default values of some options have been changed. Update your options if necessary.


The default value has been changed from true to false. Also, old Splide assigned tabindex="0" to a root element when the value is 'focused', but the new one won't because adding the attribute to non-interactive elements is discouraged. If necessary, you will have to insert it manually.


Enables shortcuts only when a carousel contains focus


Disables shortcuts


Enables shortcuts globally, listening to the window keydown event (discouraged)


Same with true

See this section for more details.


The default value has been changed from true to false. If two synced carousels had different transition speed, ignoring interaction while transitioning might cause desynchronization issue.


The default value was true, but now it is:

  • false for normal carousels
  • true when isNavitation is true

As a result of other accessibility improvements, slides in a normal carousel do not need to be focusable (probably, I'm not 100% sure), whereas slides in a thumbnail carousel with isNavigation still needs to, since clickable elements must be focusable.


The 'slider' value is no longer available. Change the value to true and follow this instruction.


The 'slider' value is no longer available. Change the value to true and follow this instruction.


New keys —carousel, slide, and slideLabel — are added. See this page for more details.

Play/Pause Button

According to feedback, users prefer a combined play-pause button for autoplay rather than separated buttons. So, I've decided to quit supporting individual buttons and to include the single toggle button.

<div class="splide">
<div class="splide__autoplay">
<button class="splide__play">Play</button>
<button class="splide__pause">Pause</button>
<button class="splide__toggle" type="button">
<span class="splide__toggle__play">Play</span>
<span class="splide__toggle__pause">Pause</span>

You can keep using separated buttons by the following snippet:

var splide = new Splide( '.splide', { autoplay: true } ).mount();
var Autoplay = splide.Components.Autoplay;
var play = splide.root.querySelector( '.splide__play' );
var pause = splide.root.querySelector( '.splide__pause' );
if ( play ) {
play.addEventListener( 'click', function () {
} );
if ( pause ) {
pause.addEventListener( 'click', function () {
} );

Slider Element

The purpose of using <div class="splide__slider"> was to wrap a track with a relative element. In the new version, it's no longer necessary since I've relaxed restriction of the HTML structure.

You can get the same result by following steps:

  1. Change arrows and/or pagination options from 'slider' to true, or just remove them since it's the default value.
    arrows: 'slider',
    arrows: true, // or remove this
    pagination: 'slider',
    pagination: true, // or remove this
  2. Replace the slider element with <div style="position: relative">, or assign a class that has position: rerative.
    <div class="splide">
    <div style="position: relative">
    <div class="splide__track">
    <div class="splide__list">...</div>

Alternatively, you can keep the slider element by adding the CSS below:

.splide__slider {
position: relative;



Moved to Controller#isBusy().


Parameters have been changed. See Controller for more details.


Parameters have been changed. See Scroll for more details.