Navigation and Dots
A complete slider with arrow buttons and a row of dots that highlight the active slide and jump to it on click. This builds on the slider instance (slider) returned by useKeenSlider() and its slideChanged event.
Full component
Section titled “Full component”<template> <div class="gallery"> <div ref="container" class="keen-slider"> <div v-for="slide in slides" :key="slide" class="keen-slider__slide slide" > {{ slide }} </div> </div>
<div class="controls"> <button :disabled="!slider" @click="slider?.prev()">←</button>
<div class="dots"> <button v-for="(_, idx) in slides" :key="idx" class="dot" :class="{ active: current === idx }" :aria-label="`Go to slide ${idx + 1}`" @click="slider?.moveToIdx(idx)" /> </div>
<button :disabled="!slider" @click="slider?.next()">→</button> </div> </div></template>
<script setup>import { ref, watch } from 'vue'
const slides = [1, 2, 3, 4, 5]const current = ref(0)
const [container, slider] = useKeenSlider({ loop: true, slides: { perView: 1 },})
watch(slider, (instance) => { if (!instance) return instance.on('slideChanged', (s) => { current.value = s.track.details?.rel ?? 0 })}, { immediate: true })</script>
<style scoped>.slide { display: flex; align-items: center; justify-content: center; height: 240px; font-size: 48px; color: #fff; background: #3f61ff;}
.controls { display: flex; align-items: center; justify-content: center; gap: 1rem; margin-top: 1rem;}
.dots { display: flex; gap: 0.5rem;}
.dot { width: 10px; height: 10px; padding: 0; border: 1px solid #ccc; border-radius: 50%; background: transparent; cursor: pointer;}
.dot.active { background: #3f61ff; border-color: #3f61ff;}</style>How it works
Section titled “How it works”slider?.prev()/slider?.next()drive the carousel. Thesliderref isnulluntil the slider mounts on the client, so the buttons are guarded with optional chaining and:disabled="!slider".slider?.moveToIdx(idx)jumps to a specific slide when a dot is clicked.- The
slideChangedevent keepscurrentin sync no matter how the slide changed — button, dot, or swipe. We readtrack.details.rel, the index relative to the visible window, which is what you want for “which dot is active.” watch(slider, ...)with{ immediate: true }attaches the event listener the moment the instance exists.
Next steps
Section titled “Next steps”- Autoplay — advance slides automatically and pause on interaction.
- Configuration —
loop,mode,slides, and responsive breakpoints.