Thumbnail navigation

Click any thumbnail to jump to that slide. The active thumbnail gets highlighted automatically.

1
2
3
4
5
1
2
3
4
5
View code
<div id="my-slider">
  <div class="demo-slide s-purple">1</div>
  <div class="demo-slide s-blue">2</div>
  <div class="demo-slide s-green">3</div>
  <div class="demo-slide s-amber">4</div>
  <div class="demo-slide s-red">5</div>
</div>

<div id="my-thumbs">
  <div class="thumb s-purple">1</div>
  <div class="thumb s-blue">2</div>
  <div class="thumb s-green">3</div>
  <div class="thumb s-amber">4</div>
  <div class="thumb s-red">5</div>
</div>
.demo-slide { height: 260px; display:flex; align-items:center; justify-content:center; font-size:2.5rem; font-weight:700; color:#fff; border-radius:8px; }
#my-thumbs { display:flex; gap:8px; margin-top:12px; }
.thumb { flex:1; height:56px; border-radius:6px; display:flex; align-items:center; justify-content:center; font-weight:700; color:#fff; opacity:0.4; transition:opacity .2s; }
.sliderkit__thumb--active { opacity:1; outline:3px solid #6C2BD9; outline-offset:2px; }
.demo-slide { height: 260px; display:flex; align-items:center; justify-content:center; font-size:2.5rem; font-weight:700; color:#fff; border-radius:8px; }
#my-thumbs { display:flex; gap:8px; margin-top:12px; }
.thumb { flex:1; height:56px; border-radius:6px; display:flex; align-items:center; justify-content:center; font-weight:700; color:#fff; opacity:0.4; transition:opacity .2s; }
.sliderkit__thumb--active { opacity:1; outline:3px solid #6C2BD9; outline-offset:2px; }
import { Slider } from '@andresclua/sliderkit'
import { thumbs } from '@andresclua/sliderkit-plugins'

new Slider('#my-slider', {
  items: 1,
  loop: false,
  speed: 300,
  plugins: [thumbs({ container: '#my-thumbs' })],
})

Many thumbnails with arrow navigation

When you have more thumbnails than fit in view, add prev/next arrows to scroll the strip. The strip auto-scrolls to keep the active thumbnail visible.

1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
View code
<div id="my-slider">
  <div class="demo-slide s-purple">1</div>
  <div class="demo-slide s-blue">2</div>
  <div class="demo-slide s-green">3</div>
  <div class="demo-slide s-amber">4</div>
  <div class="demo-slide s-red">5</div>
  <div class="demo-slide s-pink">6</div>
  <div class="demo-slide s-teal">7</div>
  <div class="demo-slide s-indigo">8</div>
  <div class="demo-slide s-purple">9</div>
  <div class="demo-slide s-blue">10</div>
</div>

<div class="thumb-nav">
  <button class="thumb-arrow thumb-arrow--prev">&#8592;</button>
  <div class="thumb-viewport">
    <div id="my-thumbs">
      <div class="thumb s-purple">1</div>
      <div class="thumb s-blue">2</div>
      <div class="thumb s-green">3</div>
      <div class="thumb s-amber">4</div>
      <div class="thumb s-red">5</div>
      <div class="thumb s-pink">6</div>
      <div class="thumb s-teal">7</div>
      <div class="thumb s-indigo">8</div>
      <div class="thumb s-purple">9</div>
      <div class="thumb s-blue">10</div>
    </div>
  </div>
  <button class="thumb-arrow thumb-arrow--next">&#8594;</button>
</div>
.demo-slide { height:260px; display:flex; align-items:center; justify-content:center; font-size:2.5rem; font-weight:700; color:#fff; border-radius:8px; }

.thumb-nav { display:flex; align-items:center; gap:8px; margin-top:12px; }
.thumb-viewport { flex:1; overflow:hidden; }
#my-thumbs { display:flex; gap:8px; }

.thumb { flex:0 0 72px; height:56px; border-radius:6px; display:flex; align-items:center; justify-content:center; font-weight:700; color:#fff; opacity:0.4; transition:opacity .2s; }
.sliderkit__thumb--active { opacity:1; outline:3px solid #6C2BD9; outline-offset:2px; }

.thumb-arrow { width:32px; height:32px; border-radius:50%; border:1px solid #e2e8f0; background:#fff; cursor:pointer; font-size:1rem; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.thumb-arrow:hover { background:#f3f4f6; }
.demo-slide { height:260px; display:flex; align-items:center; justify-content:center; font-size:2.5rem; font-weight:700; color:#fff; border-radius:8px; }

.thumb-nav { display:flex; align-items:center; gap:8px; margin-top:12px; }
.thumb-viewport { flex:1; overflow:hidden; }
#my-thumbs { display:flex; gap:8px; }

.thumb { flex:0 0 72px; height:56px; border-radius:6px; display:flex; align-items:center; justify-content:center; font-weight:700; color:#fff; opacity:0.4; transition:opacity .2s; }
.sliderkit__thumb--active { opacity:1; outline:3px solid #6C2BD9; outline-offset:2px; }

.thumb-arrow { width:32px; height:32px; border-radius:50%; border:1px solid #e2e8f0; background:#fff; cursor:pointer; font-size:1rem; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.thumb-arrow:hover { background:#f3f4f6; }
import { Slider } from '@andresclua/sliderkit'
import { thumbs } from '@andresclua/sliderkit-plugins'

const slider = new Slider('#my-slider', {
  items: 1,
  loop: false,
  speed: 300,
  plugins: [
    thumbs({ container: '#my-thumbs' }),
  ],
})

const viewport = document.querySelector('.thumb-viewport')
const strip    = document.getElementById('my-thumbs')

// arrow buttons scroll the strip
document.querySelector('.thumb-arrow--prev').addEventListener('click', () => {
  viewport.scrollBy({ left: -160, behavior: 'smooth' })
})
document.querySelector('.thumb-arrow--next').addEventListener('click', () => {
  viewport.scrollBy({ left: 160, behavior: 'smooth' })
})

// auto-scroll to keep active thumb in view on slide change
slider.on('indexChanged', () => {
  const active = strip.children[slider.activeIndex]
  if (active) active.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' })
})

// drag-to-scroll on the thumbnail strip
let isDragging = false, dragStartX = 0, dragScrollLeft = 0
viewport.style.cursor = 'grab'
viewport.addEventListener('mousedown', (e) => {
  isDragging     = true
  dragStartX     = e.pageX - viewport.offsetLeft
  dragScrollLeft = viewport.scrollLeft
  viewport.style.cursor = 'grabbing'
})
viewport.addEventListener('mouseleave', () => { isDragging = false; viewport.style.cursor = 'grab' })
viewport.addEventListener('mouseup',    () => { isDragging = false; viewport.style.cursor = 'grab' })
viewport.addEventListener('mousemove',  (e) => {
  if (!isDragging) return
  e.preventDefault()
  viewport.scrollLeft = dragScrollLeft - (e.pageX - viewport.offsetLeft - dragStartX)
})

Arrows navigate the slider

Same thumbnail strip, but now the prev/next arrows move the slider itself — the active thumbnail follows automatically.

1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
View code
<div id="my-slider">
  <div class="demo-slide s-purple">1</div>
  <div class="demo-slide s-blue">2</div>
  <div class="demo-slide s-green">3</div>
  <div class="demo-slide s-amber">4</div>
  <div class="demo-slide s-red">5</div>
  <div class="demo-slide s-pink">6</div>
  <div class="demo-slide s-teal">7</div>
  <div class="demo-slide s-indigo">8</div>
  <div class="demo-slide s-purple">9</div>
  <div class="demo-slide s-blue">10</div>
</div>

<div class="thumb-nav">
  <button class="thumb-arrow thumb-arrow--prev">&#8592;</button>
  <div class="thumb-viewport">
    <div id="my-thumbs">
      <div class="thumb s-purple">1</div>
      <div class="thumb s-blue">2</div>
      <div class="thumb s-green">3</div>
      <div class="thumb s-amber">4</div>
      <div class="thumb s-red">5</div>
      <div class="thumb s-pink">6</div>
      <div class="thumb s-teal">7</div>
      <div class="thumb s-indigo">8</div>
      <div class="thumb s-purple">9</div>
      <div class="thumb s-blue">10</div>
    </div>
  </div>
  <button class="thumb-arrow thumb-arrow--next">&#8594;</button>
</div>
.demo-slide { height:260px; display:flex; align-items:center; justify-content:center; font-size:2.5rem; font-weight:700; color:#fff; border-radius:8px; }

.thumb-nav { display:flex; align-items:center; gap:8px; margin-top:12px; }
.thumb-viewport { flex:1; overflow:hidden; }
#my-thumbs { display:flex; gap:8px; }

.thumb { flex:0 0 72px; height:56px; border-radius:6px; display:flex; align-items:center; justify-content:center; font-weight:700; color:#fff; opacity:0.4; transition:opacity .2s; cursor:pointer; }
.sliderkit__thumb--active { opacity:1; outline:3px solid #6C2BD9; outline-offset:2px; }

.thumb-arrow { width:32px; height:32px; border-radius:50%; border:1px solid #e2e8f0; background:#fff; cursor:pointer; font-size:1rem; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.thumb-arrow:hover { background:#f3f4f6; }
.demo-slide { height:260px; display:flex; align-items:center; justify-content:center; font-size:2.5rem; font-weight:700; color:#fff; border-radius:8px; }

.thumb-nav { display:flex; align-items:center; gap:8px; margin-top:12px; }
.thumb-viewport { flex:1; overflow:hidden; }
#my-thumbs { display:flex; gap:8px; }

.thumb { flex:0 0 72px; height:56px; border-radius:6px; display:flex; align-items:center; justify-content:center; font-weight:700; color:#fff; opacity:0.4; transition:opacity .2s; cursor:pointer; }
.sliderkit__thumb--active { opacity:1; outline:3px solid #6C2BD9; outline-offset:2px; }

.thumb-arrow { width:32px; height:32px; border-radius:50%; border:1px solid #e2e8f0; background:#fff; cursor:pointer; font-size:1rem; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.thumb-arrow:hover { background:#f3f4f6; }
import { Slider } from '@andresclua/sliderkit'
import { thumbs } from '@andresclua/sliderkit-plugins'

const slider = new Slider('#my-slider', {
  items: 1,
  loop: false,
  speed: 300,
  plugins: [thumbs({ container: '#my-thumbs' })],
})

const viewport = document.querySelector('.thumb-viewport')
const strip    = document.getElementById('my-thumbs')

// arrows navigate the slider, not the strip
document.querySelector('.thumb-arrow--prev').addEventListener('click', () => slider.prev())
document.querySelector('.thumb-arrow--next').addEventListener('click', () => slider.next())

// auto-scroll strip to keep active thumb in view
slider.on('indexChanged', () => {
  const active = strip.children[slider.activeIndex]
  if (active) active.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' })
})

// drag-to-scroll on the thumbnail strip
let isDragging = false, dragStartX = 0, dragScrollLeft = 0
viewport.style.cursor = 'grab'
viewport.addEventListener('mousedown', (e) => {
  isDragging     = true
  dragStartX     = e.pageX - viewport.offsetLeft
  dragScrollLeft = viewport.scrollLeft
  viewport.style.cursor = 'grabbing'
})
viewport.addEventListener('mouseleave', () => { isDragging = false; viewport.style.cursor = 'grab' })
viewport.addEventListener('mouseup',    () => { isDragging = false; viewport.style.cursor = 'grab' })
viewport.addEventListener('mousemove',  (e) => {
  if (!isDragging) return
  e.preventDefault()
  viewport.scrollLeft = dragScrollLeft - (e.pageX - viewport.offsetLeft - dragStartX)
})