Gallery
Introduction
In this tutorial, you'll learn how to control a carousel by basic APIs with creating the following gallery. When the main carousel moves, the active thumbnail will change. Also, thumbnails are clickable to navigate the main carousel.
HTML and CSS
First, let's write markup to create a carousel and thumbnails.
Make sure to describe your images by alt
:
<
section
id
=
"main-carousel"
class
=
"splide"
aria-label
=
"My Awesome Gallery"
>
<
div
class
=
"splide__track"
>
<
ul
class
=
"splide__list"
>
<
li
class
=
"splide__slide"
>
<
img
src
=
"image1.jpg"
alt
=
""
>
<
/
li
>
<
li
class
=
"splide__slide"
>
<
img
src
=
"image2.jpg"
alt
=
""
>
<
/
li
>
<
li
class
=
"splide__slide"
>
<
img
src
=
"image3.jpg"
alt
=
""
>
<
/
li
>
<
li
class
=
"splide__slide"
>
<
img
src
=
"image4.jpg"
alt
=
""
>
<
/
li
>
<
/
ul
>
<
/
div
>
<
/
section
>
<
ul
id
=
"thumbnails"
class
=
"thumbnails"
>
<
li
class
=
"thumbnail"
>
<
img
src
=
"thumbnail1.jpg"
alt
=
""
>
<
/
li
>
<
li
class
=
"thumbnail"
>
<
img
src
=
"thumbnail2.jpg"
alt
=
""
>
<
/
li
>
<
li
class
=
"thumbnail"
>
<
img
src
=
"thumbnail3.jpg"
alt
=
""
>
<
/
li
>
<
li
class
=
"thumbnail"
>
<
img
src
=
"thumbnail4.jpg"
alt
=
""
>
<
/
li
>
<
/
ul
>
HTML
<section id="main-carousel" class="splide" aria-label="My Awesome Gallery"> <div class="splide__track"> <ul class="splide__list"> <li class="splide__slide"> <img src="image1.jpg" alt=""> </li> <li class="splide__slide"> <img src="image2.jpg" alt=""> </li> <li class="splide__slide"> <img src="image3.jpg" alt=""> </li> <li class="splide__slide"> <img src="image4.jpg" alt=""> </li> </ul> </div> </section> <ul id="thumbnails" class="thumbnails"> <li class="thumbnail"> <img src="thumbnail1.jpg" alt=""> </li> <li class="thumbnail"> <img src="thumbnail2.jpg" alt=""> </li> <li class="thumbnail"> <img src="thumbnail3.jpg" alt=""> </li> <li class="thumbnail"> <img src="thumbnail4.jpg" alt=""> </li> </ul>
Then, style thumbnails as you like. This example uses this CSS:
.thumbnails
{
display
:
flex
;
margin
:
1
rem
auto
0
;
padding
:
0
;
justify-content
:
center
;
}
.thumbnail
{
width
:
70
px
;
height
:
70
px
;
overflow
:
hidden
;
list-style
:
none
;
margin
:
0
0.2
rem
;
cursor
:
pointer
;
}
.thumbnail
img
{
width
:
100
%
;
height
:
auto
;
}
CSS
.thumbnails { display: flex; margin: 1rem auto 0; padding: 0; justify-content: center; } .thumbnail { width: 70px; height: 70px; overflow: hidden; list-style: none; margin: 0 0.2rem; cursor: pointer; } .thumbnail img { width: 100%; height: auto; }
Main Carousel
Next, apply Splide to the main carousel. This example disables pagination because the carousel will have the thumbnail control:
var
splide
=
new
Splide
(
'#main-carousel'
,
{
pagination
:
false
,
}
)
;
splide
.
mount
(
)
;
JavaScript
var splide = new Splide( '#main-carousel', { pagination: false, } ); splide.mount();
Thumbnails
Okay, the most important part is coming 💪
To make thumbnails clickable, we need to listen to their click
events:
// Collects LI elements:
var
thumbnails
=
document
.
getElementsByClassName
(
'thumbnail'
)
;
for
(
var
i
=
0
;
i
<
thumbnails
.
length
;
i
++
)
{
initThumbnail
(
thumbnails
[
i
]
,
i
)
;
}
// The function to initialize each thumbnail.
function
initThumbnail
(
thumbnail
,
index
)
{
thumbnail
.
addEventListener
(
'click'
,
function
(
)
{
// move the carousel
}
)
;
}
JavaScript
// Collects LI elements: var thumbnails = document.getElementsByClassName( 'thumbnail' ); for ( var i = 0; i < thumbnails.length; i++ ) { initThumbnail( thumbnails[ i ], i ); } // The function to initialize each thumbnail. function initThumbnail( thumbnail, index ) { thumbnail.addEventListener( 'click', function () { // move the carousel } ); }
When the user clicks thumbnail, the main carousel should move to the corresponded slide.
You can move the carousel via Splide#go()
that can take a slide index:
var
splide
=
new
Splide
(
...
)
;
...
function
initThumbnail
(
thumbnail
,
index
)
{
thumbnail
.
addEventListener
(
'click'
,
function
(
)
{
splide
.
go
(
index
)
;
}
)
;
}
JavaScript
var splide = new Splide( ... ); ... function initThumbnail( thumbnail, index ) { thumbnail.addEventListener( 'click', function () { splide.go( index ); } ); }
Now we can navigate the carousel by clicking thumbnails, but the user won't be sure which thumbnail is currently selected.
To emphasize it by CSS, let's add the is-active
class to the active thumbnail.
You can toggle the class by listening to 'move'
event triggered every time when the carousel moves:
var
thumbnails
=
document
.
getElementsByClassName
(
'thumbnail'
)
;
var
current
;
// Keeps the current thumbnail
...
splide
.
on
(
'move'
,
function
(
)
{
if
(
current
)
{
current
.
classList
.
remove
(
'is-active'
)
;
}
// Splide#index returns the latest slide index:
var
thumbnail
=
thumbnails
[
splide
.
index
]
;
if
(
thumbnail
)
{
thumbnail
.
classList
.
add
(
'is-active'
)
;
current
=
thumbnail
;
}
}
)
;
JavaScript
var thumbnails = document.getElementsByClassName( 'thumbnail' ); var current; // Keeps the current thumbnail ... splide.on( 'move', function () { if ( current ) { current.classList.remove( 'is-active' ); } // Splide#index returns the latest slide index: var thumbnail = thumbnails[ splide.index ]; if ( thumbnail ) { thumbnail.classList.add( 'is-active' ); current = thumbnail; } } );
The current
variable holds the current thumbnail element so that we can remove is-active
when it changes.
By using the is-active
class, we can clarify the selected thumbnail like so:
.thumbnail
{
...
opacity
:
0.3
;
}
.thumbnail.is-active
{
opacity
:
1
;
}
CSS
.thumbnail { ... opacity: 0.3; } .thumbnail.is-active { opacity: 1; }
That's better — but as we add the class when the carousel moves, no slide is active initially.
We can fix it by the mounted
event fired right after the carousel is initialized:
splide
.
on
(
'mounted move'
,
function
(
)
{
...
}
)
;
JavaScript
splide.on( 'mounted move', function () { ... } );
We're done! 🎉 Here is the whole code of this tutorial:
12345678910111213141516171819202122232425262728293031var
splide
=
new
Splide
(
'#main-carousel'
,
{
pagination
:
false
,
}
)
;
var
thumbnails
=
document
.
getElementsByClassName
(
'thumbnail'
)
;
var
current
;
for
(
var
i
=
0
;
i
<
thumbnails
.
length
;
i
++
)
{
initThumbnail
(
thumbnails
[
i
]
,
i
)
;
}
function
initThumbnail
(
thumbnail
,
index
)
{
thumbnail
.
addEventListener
(
'click'
,
function
(
)
{
splide
.
go
(
index
)
;
}
)
;
}
splide
.
on
(
'mounted move'
,
function
(
)
{
var
thumbnail
=
thumbnails
[
splide
.
index
]
;
if
(
thumbnail
)
{
if
(
current
)
{
current
.
classList
.
remove
(
'is-active'
)
;
}
thumbnail
.
classList
.
add
(
'is-active'
)
;
current
=
thumbnail
;
}
}
)
;
splide
.
mount
(
)
;
JavaScript
var splide = new Splide( '#main-carousel', { pagination: false, } ); var thumbnails = document.getElementsByClassName( 'thumbnail' ); var current; for ( var i = 0; i < thumbnails.length; i++ ) { initThumbnail( thumbnails[ i ], i ); } function initThumbnail( thumbnail, index ) { thumbnail.addEventListener( 'click', function () { splide.go( index ); } ); } splide.on( 'mounted move', function () { var thumbnail = thumbnails[ splide.index ]; if ( thumbnail ) { if ( current ) { current.classList.remove( 'is-active' ); } thumbnail.classList.add( 'is-active' ); current = thumbnail; } } ); splide.mount();
This sample code is available in CodeSandbox too.
This gallery is not compatible with the destroy
option because Splide discards all handlers on destruction. You need to create an extension to make it work with the option.
Tips
I highly recommend improving accessibility by implementing these things:
- Assign
tabindex="0"
to thumbnails for keyboard users - Add
aria-label
to tell what happens when the user clicks each thumbnail (aria-label="Go to slide 1"
). - Add
aria-current
to the active thumbnail - Link thumbnails to each slide by
aria-controls