The purpose of this tutorial is to create a slider with image thumbnails which behave as tab navigation. If you are looking for a thumbnail slider, visit this tutorial page. Note that you need to have finished setting up Splide before start.

Main Slider

At first, let’s prepare the main slider, referring to the Image Slider tutorial. Pagination is disabled in the following example since the slider is planned to come with clickable thumbnails.

document.addEventListener( 'DOMContentLoaded', function () {
	new Splide( '#splide', {
		rewind     : true,
		heightRatio: 0.5,
		pagination : false,
	} );
} );

Image Thumbnails

Next, enumerate thumbnails by HTML and style them CSS as you like.

<div class="thumbnails js-thumbnails">
	<ul class="thumbnails__list">
		<li class="thumbnails__item" role="button" tabindex="0">
			<img src=thumbnail01.jpg alt="Thumbnail 01">
		</li>
		<li class="thumbnails__item" role="button" tabindex="0">
			<img src=thumbnail02.jpg alt="Thumbnail 02">
		</li>
	</ul>
</div>

To make thumbnails behave as navigation, we need to implement at least following things:

  • Listen a click event of each thumbnail
  • Move the main slider when a thumbnail is clicked
  • Toggle 'is-active' status class for styling

Here is an example code including these 3 points:

document.addEventListener( 'DOMContentLoaded', function () {
	var splide = new Splide( '#splide-gallery' ).mount();
	// Collect elements of thumbnails.
	var images = document.querySelectorAll( '.js-thumbnails li' );

	var activeImage;
	var activeClass = 'is-active';

	// Listen a click event and toggle a class.
	for ( let i = 0, len = images.length; i < len; i++ ) {
		var image = images[ i ];

		splide.on( 'click', function () {
			if ( activeImage !== image ) {
				activeImage.classList.remove( activeClass );
				image.classList.add( activeClass );
				splide.go( i );
				activeImage = image;
			}
		}, image );
	}
} );

The go() is the method that moves a slider by providing a control pattern. A destination slide index is passed to it in the example above.

Although this example works well, it’s not adequate because an active thumbnail is not updated when the main slider is manually moved. We need to tell the status of the main slider to thumbnails, utilizing the on() method for observing change of the active slide index.

document.addEventListener( 'DOMContentLoaded', function () {
	var splide = new Splide( '#splide-gallery' );
	var images = document.querySelectorAll( '.js-thumbnails li' );

	var activeImage;
	var activeClass = 'is-active';

	for ( let i = 0, len = images.length; i < len; i++ ) {
		var image = images[ i ];

		splide.on( 'click', function () {
			if ( activeImage !== image ) {
				if ( activeImage ) {
					activeImage.classList.remove( activeClass );
				}

				image.classList.add( activeClass );
				activeImage = image;
				splide.go( i );
			}
		}, image );
	}
	
	// Listen a move event to change the active preview image.
	splide.on( 'move', function ( newIndex ) {
		var image = images[ newIndex ];

		if ( image && activeImage !== image ) {
			if ( activeImage ) {
				activeImage.classList.remove( activeClass );
			}

			image.classList.add( activeClass );
			activeImage = image;
		}
	} );
	
	splide.mount();
} );

Be aware that mount() method is moved from the top to the bottom.

The move event is triggered when the main slider starts moving, telling us the next active index through the first argument of a callback. As you may have already guessed, the process updating an active thumbnail in the callback of the click event is redundant since the move event is also fired after thumbnails are clicked, and then an active thumbnail will be updated by the newly defined callback.

The last thing to be considered is to initially activate the thumbnail corresponding to the first slide index. Because the index can be changed by the start option, there is the possibility that it’s not 0. You can get it after “mount” process:

slider.on( 'mounted', function () {
	var image = images[ slider.index ];

	if ( image && activeImage !== image ) {
		if ( activeImage ) {
			activeImage.classList.remove( activeClass );
		}

		image.classList.add( activeClass );
		activeImage = image;
	}
} );

You see the two anonymous functions passed to move and mounted are quite similar. As the mounted event doesn’t provide any parameters, they can be easily merged.

Here is the whole example code of this tutorial.

document.addEventListener( 'DOMContentLoaded', function () {
	var splide = new Splide( '#splide-gallery' );
	var images = document.querySelectorAll( '.js-thumbnails li' );

	var activeImage;
	var activeClass = 'is-active';

	for ( let i = 0, len = images.length; i < len; i++ ) {
		var image = images[ i ];

		splide.on( 'click', function () {
			if ( activeImage !== image ) {
				splide.go( i );
			}
		}, image );
	}
	
	splide.on( 'mounted move', function ( newIndex ) {
		// newIndex will be undefined through the "mounted" event.
		var image = images[ newIndex !== undefined ? newIndex : splide.index ];

		if ( image && activeImage !== image ) {
			if ( activeImage ) {
				activeImage.classList.remove( activeClass );
			}

			image.classList.add( activeClass );
			activeImage = image;
		}
	} );
	
	splide.mount();
} );

Finally, you will get like the following gallery:

User's Guide
Tutorials
Extensions
Integration