
Splide is a lightweight, responsive, accessible, mobile-friendly, full-featured slider/carousel plugin implemented in pure JavaScript and CSS/CSS3.
More features:
- Touch-enabled. Supports both touch swipe and mouse drag.
- Smooth slide & fade transitions based on CSS3.
- Image lazy loading.
- Supports nested sliders.
- Supports HTML video, YouTube or Vimeo videos.
- Allows multiple items on a slide.
- Autoplay.
- URL hash change.
- RTL mode.
- Horizontal and vertical directions.
Basic usage:
Install and import the Splide library.
# Core $ npm install @splidejs/splide --save # Video Extension $ npm install @splidejs/splide-extension-video --save # URL Hash Change Extension $ npm install @splidejs/splide-extension-url-hash --save
// Core import splide from '@splidejs/splide'; // Video Extension import Video from '@splidejs/splide-extension-video'; // URL Hash Change Extension import URLHash from '@splidejs/splide-extension-url-hash';
Alternatively, you can directly load the necessary JavaScript and CSS files in the document.
<!-- Core --> <link rel="stylesheet" href="dist/css/splide.min.css"> <script src="dist/js/splide.min.js"></script> <!-- Video Extension --> <link rel="stylesheet" href="splide-extension-video/dist/css/splide-extension-video.min.css"> <script src="splide-extension-video/dist/js/splide-extension-video.min.js"></script> <!-- URL Hash Change Extension --> <script src="splide-extension-url-hash/dist/js/splide-extension-url-hash.min.js"></script>
Insert any content as slides to the slider.
<div class="splide">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide">Slide 01</li>
<li class="splide__slide">Slide 02</li>
<li class="splide__slide">Slide 03</li>
<li class="splide__slide">Slide 04</li>
<li class="splide__slide">Slide 05</li>
</ul>
</div>
</div><div class="splide">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide">
<div class="splide__slide__container">
<img src="1.jpg">
</div>
Slide 1
</li>
<li class="splide__slide">
<div class="splide__slide__container">
<img src="2.jpg">
</div>
Slide 2
</li>
<li class="splide__slide">
<div class="splide__slide__container">
<img src="3.jpg">
</div>
Slide 3
</li>
</ul>
</div>
</div>You might need a progress bar on the Autoplay mode that indicates the time to wait before transitioning to the next slide.
<div class="splide__progress"> <div class="splide__progress__bar"> </div> </div>
Invoke the slider plugin with default options. That’s it.
new Splide( '.splide' ).mount();
Create a video carousel using the Video extension.
<div class="splide">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide" data-splide-youtube="YOUTUBE VIDEO URL">
<img src="cover.jpg">
</li>
<li class="splide__slide" data-splide-vimeo="VIMEO VIDEO URL">
<img src="cover.jpg">
</li>
</ul>
</div>
</div>new Splide( '#splide', {
video: {
// options here
},
}).mount(window.splide.Extensions);Enable the URL hash change extension.
<div class="splide">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide" data-splide-hash="slide01"></li>
<li class="splide__slide" data-splide-hash="slide02"></li>
<li class="splide__slide" data-splide-hash="slide03"></li>
</ul>
</div>
</div>new Splide( '#splide' ).mount(window.splide.Extensions);
All possible options to customize the slider.
new Splide( '.splide' , {
/**
* The type of the slider.
* - 'slide': A slider with the slide transition
* - 'loop' : A carousel slider
* - 'fade' : A slider with the fade transition. This does not support the perPage option.
*/
type?: string;
/**
* Determines whether to disable any actions while the slider is transitioning.
* Even if `false`, the slider forcibly waits for transition on the loop points.
*/
waitForTransition?: boolean;
/**
* If `true`, the width of slides are determined by their width.
* The `perPage` and `perMove` options should be `1`.
*/
autoWidth?: boolean;
/**
* If `true`, the height of slides are determined by their height.
* The `perPage` and `perMove` options should be `1`.
*/
autoHeight?: boolean;
/**
* The start index.
*/
start?: number;
/**
* Changes the arrow SVG path, like 'm7.61 0.807-2.12...'.
*/
arrowPath?: string;
/**
* Determines whether to activate autoplay or not.
* If `paused`, it will not begin when the slider becomes active.
* You need to provided play/pause buttons or manually start it by `Autoplay#play()`.
*/
autoplay?: boolean | 'pause';
/**
* The autoplay interval in milliseconds.
*/
interval?: number;
/**
* Determines whether to pause autoplay on mouseover.
*/
pauseOnHover?: boolean;
/**
* Determines whether to pause autoplay when the slider contains the active element (focused element).
* This should be `true` for accessibility.
*/
pauseOnFocus?: boolean;
/**
* Determines whether to reset the autoplay progress when it is requested to start again.
*/
resetProgress?: boolean;
/**
* Enables lazy loading.
* Provide the `src` by the `data-splide-lazy` or the `srcset` by the `data-splide-lazy-srcset`.
* You may also provide `src` for the placeholder, but the value must be different with the data.
*
* - `false`: Disables lazy loading
* - `'nearby'`: Starts loading only images around the active slide (page)
* - `'sequential'`: Loads images sequentially
*/
lazyLoad?: boolean | 'nearby' | 'sequential';
/**
* Determine how many pages (not slides) around the active slide should be loaded beforehand.
* This only works when the `lazyLoad` option is `'nearby'`.
*/
preloadPages?: number;
/**
* Determines whether to enable keyboard shortcuts or not.
* - `true` or `'global'`: Listens to the `keydown` event of the document.
* - 'focused': Listens to the `keydown` event of the slider root element with adding `tabindex="0"` to it.
* - `false`: Disables keyboard shortcuts.
*/
keyboard?: boolean | string;
/**
* Enables navigation by the mouse wheel.
* The `waitForTransition` option should be `true`.
*/
wheel?: boolean;
/**
* Determines whether to release the wheel event when the slider reaches the first or last slide
*/
releaseWheel?: boolean;
/**
* The direction of the slider.
* - 'ltr': Left to right
* - 'rtl': Right to left
* - 'ttb': Top to bottom
*/
direction?: 'ltr' | 'rtl' | 'ttb';
/**
* Converts the image `src` to the css `background-image` URL of the parent element.
* This requires `fixedHeight` or `heightRatio` option.
*/
cover?: boolean;
/**
* Determines whether to add `tabindex="0"` to visible slides or not.
*/
slideFocus?: boolean;
/**
* If `true`, the slider makes slides clickable to navigate another slider.
* Use `Splide#sync()` to sync multiple sliders.
*/
isNavigation?: boolean;
/**
* Determines whether to trim spaces before/after the slider if the `focus` option is available.
* - `true`: Trims spaces. The slider may stay on the same location even when requested to move.
* - `'move'`: Trims spaces and focuses to move the slider when requested.
*/
trimSpace?: boolean | 'move';
/**
* Updates the `is-active` status of slides just before moving the slider.
*/
updateOnMove?: boolean;
/**
* If `true` and the `focus` option is available:
* - Disables the next arrow when a carousel reaches the last page even if the active slide is not the last slide.
* - Omits redundant pagination dots which just change the active slide and do not move a carousel.
*/
omitEnd?: boolean;
/**
* If `min`, the media query for breakpoints will be `min-width`, or otherwise, `max-width`.
*/
mediaQuery?: 'min' | 'max';
/**
* The selector to get focusable elements
* where `tabindex="-1"` will be assigned when their ascendant slide is hidden.
*/
focusableNodes?: string,
/**
* Determines whether to use the Transition component or not.
*/
useScroll?: boolean;
/**
* Options for specific breakpoints.
*
* @example
* ```ts
* {
* 1000: {
* perPage: 3,
* gap : 20
* },
* 600: {
* perPage: 1,
* gap : 5,
* },
* }
* ```
*/
breakpoints?: Record,
/**
* The collection of class names.
*/
classes?: Record<string, string>;
/**
* The collection of i18n strings.
*/
i18n?: Record<string, string>;
}
/**
* The interface for options that can correspond with breakpoints.
*
* @since 3.0.0
*/
export interface ResponsiveOptions {
/**
* Accepts arbitrary properties for extensions, although it's not ideal typing.
*/
[ key: string ]: any;
/**
* Determines whether to rewind the slider or not.
*/
rewind?: boolean;
/**
* The transition speed in milliseconds.
*/
speed?: number;
/**
* The transition speed on rewind in milliseconds.
*/
rewindSpeed?: number;
/**
* Defines the slider max width, accepting the CSS format such as 10em, 80vw.
*/
width?: number | string;
/**
* Defines the slider height, accepting the CSS format.
*/
height?: number | string;
/**
* Fixes width of slides, accepting the CSS format.
* The slider will ignore the `perPage` option if you provide this value.
*/
fixedWidth?: number | string;
/**
* Fixes height of slides, accepting the CSS format.
* The slider will ignore the `heightRatio` option if you provide this value.
*/
fixedHeight?: number | string;
/**
* Determines height of slides by the ratio to the slider width.
* For example, when the slider width is `1000` and the ratio is `0.5`, the height will be `500`.
*/
heightRatio?: number;
/**
* Determines the number of slides to display in a page.
*/
perPage?: number;
/**
* Determines the number of slides to move at once.
*/
perMove?: number;
/**
* Determine the number of clones on each side of the slider.
* In most cases, you don't need to provide this value.
*/
clones?: number;
/**
* Determines which slide should be active if there are multiple slides in a page.
* Numbers and `'center'` are acceptable.
*/
focus?: number | 'center';
/**
* The gap between slides. The CSS format is acceptable, such as `1em`.
*/
gap?: number | string;
/**
* Sets padding left/right or top/bottom of the slider.
* The CSS format is acceptable, such as `1em`.
*
* @example
* ```ts
* // By number
* padding: 10,
*
* // By the CSS format
* padding: '1rem',
*
* // Specifies each value for a horizontal slider
* padding: { left: 10, right: 20 },
* padding: { left: '1rem', right: '2rem' },
*
* // Specified each value for a vertical slider
* padding: { top: 10, bottom: 20 },
* ```
*/
padding?:
| number
| string
| { left?: number | string, right?: number | string }
| { top?: number | string, bottom?: number | string };
/**
* Determines whether to create/find arrows or not.
*/
arrows?: boolean | 'slider';
/**
* Determines whether to create pagination (indicator dots) or not.
*/
pagination?: boolean | 'slider';
/**
* The timing function for the CSS transition. For example, `linear`, ease or `cubic-bezier()`.
*/
easing?: string;
/**
* The easing function for the drag free mode.
* The default function is the `easeOutQuart` interpolation.
*/
easingFunc?: ( t: number ) => number;
/**
* Determines whether to allow to drag the slider or not.
* If `free`, the slider does not snap to a slide after drag.
*/
drag?: boolean | 'free';
/**
* The selector for nodes that cannot be dragged
*/
noDrag?: selector;
/**
* The required distance to start moving the slider by the touch action.
* If you want to define the threshold for the mouse, provide an object.
*/
dragMinThreshold?: number | { mouse: number, touch: number };
/**
* Determine the power of "flick". The larger number this is, the farther the slider runs.
* Around 500 is recommended.
*/
flickPower?: number;
/**
* Limies the number of pages to move by "flick".
*/
flickMaxPages?: number;
/**
* Destroys the slider.
*/
destroy?: boolean | 'completely';
}).mount();Possible options for the video extension.
new Splide( '.splide' , {
video: {
/**
* Whether to play the video automatically.
*
* @type {boolean}
*/
autoplay: false,
/**
* Hide the video control UI.
*
* @type {boolean}
*/
hideControls: false,
/**
* Hide full screen button.
* Only for YouTube.
*
* @type {boolean}
*/
disableFullScreen: false,
/**
* Loop the video.
*
* @type {boolean}
*/
loop: false,
/**
* Mute the video.
*
* @type {boolean}
*/
mute: false,
/**
* Default volume(0.0-1.0).
*
* @type {number}
*/
volume: 0.2
}
})You can also pass the options via HTML data attributes as follows:
<div class="splide" data-splide="{OPTIONS HERE}">
</div>Event listeners.
instance.on( 'mounted', function () {
// do something
});
instance.on( 'updated', function (OPTIONS) {
// do something
});
instance.on( 'move', function (newIndex, oldIndex, destIndex) {
// do something
});
instance.on( 'moved', function (newIndex, oldIndex, destIndex) {
// do something
});
instance.on( 'drag', function (info) {
// do something
});
instance.on( 'dragged', function (info) {
// do something
});
instance.on( 'visible', function (slideObject) {
// do something
});
instance.on( 'hidden', function (slideObject) {
// do something
});
instance.on( 'active', function (slideObject) {
// do something
});
instance.on( 'inactive', function (slideObject) {
// do something
});
instance.on( 'click', function (slideObject) {
// do something
});
instance.on( 'arrows:mounted', function (prev, next) {
// do something
});
instance.on( 'arrows:updated', function (prev, next, prevIndex, nextIndex) {
// do something
});
instance.on( 'pagination:mounted', function (data, activeItem:) {
// do something
});
instance.on( 'pagination:updated', function (data, prevItem, nextItem) {
// do something
});
instance.on( 'navigation:mounted', function (Splide) {
// do something
});
instance.on( 'autoplay:play', function () {
// do something
});
instance.on( 'autoplay:pause', function () {
// do something
});
instance.on( 'autoplay:playing', function () {
// do something
});
instance.on( 'lazyload:loaded', function () {
// do something
});
instance.on( 'video:play', function (player) {
// do something
});
instance.on( 'video:paused', function (player) {
// do something
});
instance.on( 'video:ended', function (player) {
// do something
});Properties.
// root element splide.root // zero-based active index splide.index // options splide.options // the number of slides splide.length // a collection of CSS classes splide.classes // i18n splide.i18n // an object containing all components splide.Components // set/get state // CREATED = 1: Splide instance has just been created. // MOUNTED = 2: All components have been mounted. // IDLE = 3: Idling. // MOVING = 4: The slider is moving. splide.State.is( 4 ) splide.State.set( 2 )
API methods.
// go to a specific slide
// {number}: Go to slide specified by {number}.
// '+','+{number}': Increase active slide index.
// '-','-{number}': Decrease active slide index.
// '>','>{number}': Go to next page or the page specified by {number}. For example, '>2' moves a slider to page 2.
// '<','<{number}': Go to previous page or the page specified by {number}.
splide.go(0);
// check the slider type
// SLIDE = 'slide'
// LOOP = 'loop'
// FADE = 'fade'
splide.is( 'loop' );
// register a Splide instance for sync
// must be called before mount().
splide.sync( splide );
// add a new slide
splide.add( slide, index );
// remove a slide
splide.remove( index );
// refresh the slider
splide.refresh();
// destroy the slider
splide.destroy();Changelog:
v4.1.3 (09/22/2022)
- Make Splide work with elements that come from other realms, such as an iframe
v4.1.2 (09/22/2022)
- Fix typing for general components since they do not always exis
v4.1.1 (09/20/2022)
- Check whether the total width of slides is enough wide for a carousel. When detecting the status change, toggle the new is-overflow class on the root element and emits the overflow event. This also allows you to center contents when there are not enough slides. Visit this page for more details.
- Add the omitEnd option that omits some pagination dots that do not move a carousel but just change the active slide. Also, it disables the next arrow when a carousel reaches the last page. Visit this page for more details.
- Use the height of the tallest slide in the fade type for consistency with other types
- Bugfixes
v4.0.14 (09/04/2022)
- Bugfixes
v4.0.13 (09/03/2022)
- Bugfixes
v4.0.7 (06/11/2022)
- Bugfixes
v4.0.3 (05/26/2022)
- Bugfixes
v4.0.2 (05/14/2022)
- Bugfixes
v4.0.1 (04/07/2022)
- Performance optimization. Keep user options after breakpoints hit.
v4.0.0 (04/05/2022)
- Add the “svelte” field. Export some constants.
v3.6.14 (02/23/2022)
- Refactoring the Drag component with changedTouches. Disable `touch-callout` by default if the drag is enabled.
v3.6.13 (02/22/2022)
- Bug Fix: Need to hide custom arrows on initialization if available
v3.6.12 (01/27/2022)
- Bugfix
v3.6.9 (12/04/2021)
- Bugfix
v3.6.8 (12/01/2021)
- Adjust loading spinner and focus styles.
v3.6.4 (11/23/2021)
- Performance optimization.
v3.6.1(11/22/2021)
- Add the disable method to the Keyboard component
- Bug Fix
v3.5.8 (11/18/2021)
- Some bug fixes related with the “drag free” mode.
v3.5.4 (11/18/2021)
- Add the is-active class to clones.
v3.5.0 (11/16/2021)
- Add data-splide-interval to override the autoplay interval for the specific slide.
v3.4.2 (11/16/2021)
- Add the releaseWheel option that releases the wheel event when the slider reaches the first or last slide so that the user can keep scrolling the page.
v3.3.0 (11/11/2021)
- Revise the sync process
- Delete the force “waiting” point
- Bug Fix
v3.2.6 (11/06/2021)
- Bugfix: Failed to sync indices in the loop mode when using arrow keys
v3.2.5 (11/05/2021)
- Bugfix: The target slide index is incorrect in the loop mode when going back from the page that does not have enough slides
v3.2.2 (11/03/2021)
- Fix the padding bug
- Add the noDrag option
v3.1.2 (10/09/2021)
- Bug Fix: Should not remove predefined inline styles of slides.
v3.1.1 (10/07/2021)
- The dragMinThreshold option accepts an object to define the value for mouse drag.
v3.0.8 (10/07/2021)
- Bug Fix: addEventListenerOptions should be same among all drag handlers.
v3.0.7 (10/07/2021)
- Bugfix and improve performance
v3.0.2 (10/06/2021)
- Rewrite all scripts by TypeScript
- Reduce the code size (29KB → 26KB), keeping all features of the v2
- Add 300+ test cases to make the library more stable
- Implement the free drag mode
- Implement the simple mouse wheel navigation for a vertical slider
- Support sync with multiple sliders
- Support the min-width media query for breakpoints
- Handle passive event listeners where Lighthouse complains
- Solve the window reference error for SSR
- Assign is-prev to a previous slide and is-next to a next one
v2.4.24 (08/13/2021)
- Bug Fix
v2.4.21 (12/01/2020)
- Bug Fix
v2.4.20 (11/22/2020)
- Fixed: The last image missed is-visible class on zoom
v2.4.19 (11/21/2020)
- Fixed: is-visible class was sometimes not updated correctly
v2.4.18 (11/20/2020)
- Fixed: Autoplay progress was not reset when arrows were click
- Fixed: add() and remove() didn’t work correctly in loop mode
v2.4.15/16 (11/19/2020)
- Fixed: Minute drag prevents other child event listeners from firing
v2.4.14 (11/17/2020)
- Update dependencies.
v2.4.13 (08/30/2020)
- Bug Fix: Prevent click while dragging the slider in fade mode
v2.4.12 (08/24/2020)
- Fixed: Autoplay was not properly resumed on blur.
v2.4.11 (08/17/2020)
- Fixed: The track position was wrong in RTL mode.
- Fixed the invalid CSS property name.
v2.4.10 (07/30/2020)
- Fixed: Relative units(em, rem, etc) for the fixedWidth/fixedHeight option didn’t work.
v2.4.8 (07/26/2020)
- Bug Fix: mount() was called twice when destroy() and mount() were called manually, because of the breakpoint component.
v2.4.8 (07/17/2020)
- The Lazyload component accepts a srcset attribute
v2.4.6 (07/14/2020)
- Fixed Padding became undefined when the Splide instance was converted to JSON by JSON.stringify.
- Fixed Padding and gap were not updated correctly on resize if they were described by % or vw.
v2.4.4 (06/23/2020)
- Bugfix: Drag/swipe didn’t work correctly.
- Bugfix: Transition animation was skipped only in the first page of a RTL slider.
v2.4.3 (06/21/2020)
- Can select the target of the keyboard event from the document or the root element.
- Can remove tab indices from slides by slideFocus option.
- Can determine whether to prevent any actions while transitioning or not by the waitForTransition option.
- Change the way of the Layout calculation.
- Merge the horizontal and vertical sub components into the Track component.
v2.4.1 (06/20/2020)
- Optimization. Remove horizontal and vertical directions of the Track component.
v2.4.0 (06/17/2020)
- Support drag for the fade type.
v2.3.8 (06/05/2020)
- The number of clones can be determined by options.
- Fixed: Loop didn’t work well when fixedWidth is provided and number of slides is not enough to fill the view port.
v2.3.6 (05/31/2020)
- Fixed: invalid realIndex was assigned to a slide when the length of slides were less than perPage.
- Emit click event when a slide is clicked.
- All components will be evaluated again when the Splide is remounted.
v2.3.5 (05/29/2020)
- Bug Fix: Invalid realIndex was assigned to a slide when the length of slides were less than perPage.
v2.3.2 (05/28/2020)
- Bug Fix: perMove didn’t work properly with autoplay
v2.3.1 (05/21/2020)
- Bug Fix: The “is-active” class was not inserted the active slide when the updateOnMove option was true
v2.2.7 (05/17/2020)
- Breakpoints support “drag” and “pagination”.
- Throttle duration for the resize event can be changed through options.
v2.2.7 (05/05/2020)
- Bug Fix: Slide width was wrong when the window scrollbar was made hidden by the Layout component.
v2.2.6 (05/04/2020)
- Resolve a conflict with prototype.js.
v2.2.5 (04/30/2020)
- Support a hierarchical selector for initialization:
new Splide(".container .splide-container .splide"); - Fixed an error occurred when “destroy” was true and “arrows” was false.
v2.2.4 (04/15/2020)
- You can config the Thresholds for drag angle and swipe distance
- Remove the difference between splide.js and splide.min.js
v2.2.3 (03/25/2020)
- Added
type="button"attribute to buttons of pagination and arrows
v2.2.1 (02/16/2020)
- Bug Fix: Window location was changed only in Safari when arrows or thumbnails were clicked
v2.2.0 (02/14/2020)
- Add some themes to change slider appearance.
v2.1.0 (02/13/2020)
- Bug Fix: Hide broken image icons.
v2.0.1 (02/07/2020)
- Auto Width is implemented. Each slide can have its own width.
- Breakpoints accept ‘destroy’ option.
- Merge Slides component to Elements.
v1.4.1 (02/01/2020)
- Splide can be destroyed.
- Add/remove slides dynamically by API.
v1.3.4 (01/12/2020)
- Expose state constants to access them from other scripts.
v1.3.3 (01/09/2020)
- Fixed: perMove was not updated according to the breakpoints option.
v1.3.2 (01/08/2020)
- Fixed version number
- Updated package.
v1.3.1 (12/20/2019)
- Add the updateOnMove option which changes the update timing of adding is-active/is-visible classes.
v1.2.7 (11/28/2019)
- Bug Fix: Arrows were not shown in fade mode because of z-index.
v1.2.5 (11/25/2019)
- Prevent propagation of click events during drag/swipe, even if listeners are added by script.
- Disable dragging anchors.
v1.2.4 (11/24/2019)
- Prevent dragging an image itself inside a slide.
- Add Links component that prevents clicking links(anchors) while a slide is dragged/swiped.
v1.2.3 (11/24/2019)
- Fix wrong comments(data-splide-src -> data-splide-lazy).







It looks great. But I cannot get it to advance however. Also, my splide list goes out past the width of my page and all pics are visible at the same time. I looked through options and tried many things… but I am about ready to give up. I followed examples from the Splide site exactly and they did not work for me.