Skip to main content

Keen Slider

keen-slider is a third-party library. Please refer to its official documentation for more details.

You may refer to this link on how to implement rtl support for keen-slider

warning

It is essential to ensure that when incorporating the keen-slider component into your project, it is correctly wrapped using the AppKeenSlider component. In scenarios where only a single instance of keen-slider is utilized, it should be individually enclosed within the AppKeenSlider component. Conversely, if multiple instances of keen-slider are used in one page, it becomes necessary to wrap the entire page with the AppKeenSlider component to ensure optimal styles.

Basic
swiper 1
swiper 2
swiper 3
swiper 4
swiper 5

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'

const SwiperBasic = () => {
// Hooks
const [ref] = useKeenSlider<HTMLDivElement>()

return (
<div ref={ref} className='keen-slider'>
<div className='keen-slider__slide'>
<img src='/images/banners/1.jpg' alt='swiper 1' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/2.jpg' alt='swiper 2' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/3.jpg' alt='swiper 3' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/4.jpg' alt='swiper 4' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/5.jpg' alt='swiper 5' />
</div>
</div>
)
}

export default SwiperBasic
Loop
swiper 7
swiper 8
swiper 9
swiper 10

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'

const SwiperLoop = () => {
// Hooks
const [ref] = useKeenSlider<HTMLDivElement>({
loop: true
})

return (
<div ref={ref} className='keen-slider'>
<div className='keen-slider__slide'>
<img src='/images/banners/7.jpg' alt='swiper 7' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/8.jpg' alt='swiper 8' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/9.jpg' alt='swiper 9' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/10.jpg' alt='swiper 10' />
</div>
</div>
)
}

export default SwiperLoop
Multiple Slides
swiper 11
swiper 12
swiper 13
swiper 14
swiper 15

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'

const SwiperMultipleSlides = () => {
// Hooks
const [ref] = useKeenSlider<HTMLDivElement>({
slides: {
perView: 2
}
})

return (
<div ref={ref} className='keen-slider'>
<div className='keen-slider__slide'>
<img src='/images/banners/11.jpg' alt='swiper 11' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/12.jpg' alt='swiper 12' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/13.jpg' alt='swiper 13' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/14.jpg' alt='swiper 14' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/15.jpg' alt='swiper 15' />
</div>
</div>
)
}

export default SwiperMultipleSlides
Spacing
swiper 16
swiper 17
swiper 18
swiper 19
swiper 20

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'

const SwiperSpacing = () => {
// Hooks
const [ref] = useKeenSlider<HTMLDivElement>({
slides: {
perView: 2,
spacing: 16
}
})

return (
<div ref={ref} className='keen-slider'>
<div className='keen-slider__slide'>
<img src='/images/banners/16.jpg' alt='swiper 16' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/17.jpg' alt='swiper 17' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/18.jpg' alt='swiper 18' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/19.jpg' alt='swiper 19' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/20.jpg' alt='swiper 20' />
</div>
</div>
)
}

export default SwiperSpacing
FreeMode
swiper 21
swiper 22
swiper 23
swiper 24
swiper 25

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'

const SwiperFreeMode = () => {
// Hooks
const [ref] = useKeenSlider<HTMLDivElement>({
loop: true,
mode: 'free',
slides: {
perView: 2,
spacing: 16
}
})

return (
<div ref={ref} className='keen-slider'>
<div className='keen-slider__slide'>
<img src='/images/banners/21.jpg' alt='swiper 21' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/22.jpg' alt='swiper 22' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/23.jpg' alt='swiper 23' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/24.jpg' alt='swiper 24' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/25.jpg' alt='swiper 25' />
</div>
</div>
)
}

export default SwiperFreeMode
Centered
swiper 16
swiper 17
swiper 18
swiper 19
swiper 20

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'

const SwiperCentered = () => {
// Hooks
const [ref] = useKeenSlider<HTMLDivElement>({
slides: {
perView: 2,
spacing: 16,
origin: 'center'
}
})

return (
<div ref={ref} className='keen-slider'>
<div className='keen-slider__slide'>
<img src='/images/banners/16.jpg' alt='swiper 16' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/17.jpg' alt='swiper 17' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/18.jpg' alt='swiper 18' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/19.jpg' alt='swiper 19' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/20.jpg' alt='swiper 20' />
</div>
</div>
)
}

export default SwiperCentered
Vertical
1
2
3
4
5
6
7
8
9
10

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'

const SwiperVertical = () => {
// Hooks
const [ref] = useKeenSlider<HTMLDivElement>({
vertical: true,
slides: {
perView: 2,
spacing: 8
}
})

return (
<div ref={ref} className='keen-slider vertical max-bs-[300px]'>
{[...Array(10).keys()].map((num: number) => (
<div key={num} className='keen-slider__slide default-slide'>
{num + 1}
</div>
))}
</div>
)
}

export default SwiperVertical
Controls

// React Imports
import { useState } from 'react'

// MUI Imports
import Badge from '@mui/material/Badge'

// Third-party Components
import classnames from 'classnames'
import { useKeenSlider } from 'keen-slider/react'

const SwiperControls = () => {
// States
const [loaded, setLoaded] = useState<boolean>(false)
const [currentSlide, setCurrentSlide] = useState<number>(0)

// Hooks
const [sliderRef, instanceRef] = useKeenSlider<HTMLDivElement>({
slideChanged(slider) {
setCurrentSlide(slider.track.details.rel)
},
created() {
setLoaded(true)
}
})

return (
<>
<div className='navigation-wrapper'>
<div ref={sliderRef} className='keen-slider'>
<div className='keen-slider__slide'>
<img src='/images/banners/1.jpg' alt='swiper 1' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/2.jpg' alt='swiper 2' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/3.jpg' alt='swiper 3' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/4.jpg' alt='swiper 4' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/5.jpg' alt='swiper 5' />
</div>
</div>
{loaded && instanceRef.current && (
<>
<i
className={classnames('ri-arrow-left-s-line arrow arrow-left', {
'arrow-disabled': currentSlide === 0
})}
onClick={(e: any) => e.stopPropagation() || instanceRef.current?.prev()}
/>

<i
className={classnames('ri-arrow-right-s-line arrow arrow-right', {
'arrow-disabled': currentSlide === instanceRef.current.track.details.slides.length - 1
})}
onClick={(e: any) => e.stopPropagation() || instanceRef.current?.next()}
/>
</>
)}
</div>
{loaded && instanceRef.current && (
<div className='swiper-dots'>
{[...Array(instanceRef.current.track.details.slides.length).keys()].map(idx => {
return (
<Badge
key={idx}
variant='dot'
component='div'
className={classnames({
active: currentSlide === idx
})}
onClick={() => {
instanceRef.current?.moveToIdx(idx)
}}
></Badge>
)
})}
</div>
)}
</>
)
}

export default SwiperControls
Thumbnails
swiper 1
swiper 2
swiper 3
swiper 4
swiper 5
swiper 1
swiper 2
swiper 3
swiper 4
swiper 5

// React Imports
import type { MutableRefObject } from 'react'

// MUI Imports
import { useTheme } from '@mui/material/styles'

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'
import type { KeenSliderPlugin, KeenSliderInstance } from 'keen-slider/react'

const ThumbnailPlugin = (mainRef: MutableRefObject<KeenSliderInstance | null>): KeenSliderPlugin => {
return slider => {
const removeActive = () => {
slider.slides.forEach(slide => {
slide.classList.remove('active')
})
}

const addActive = (idx: number) => {
slider.slides[idx].classList.add('active')
}

const addClickEvents = () => {
slider.slides.forEach((slide, idx) => {
slide.addEventListener('click', () => {
if (mainRef.current) mainRef.current.moveToIdx(idx)
})
})
}

slider.on('created', () => {
if (!mainRef.current) return
addActive(slider.track.details.rel)
addClickEvents()
mainRef.current.on('animationStarted', main => {
removeActive()
const next = main.animator.targetIdx || 0

addActive(main.track.absToRel(next))
slider.moveToIdx(next)
})
})
}
}

const SwiperThumbnails = () => {
// Hooks
const theme = useTheme()
const [sliderRef, instanceRef] = useKeenSlider<HTMLDivElement>()
const [thumbnailRef] = useKeenSlider<HTMLDivElement>(
{
slides: {
perView: 4,
spacing: 16
},
breakpoints: {
[`(max-width: ${theme.breakpoints.values.sm}px)`]: {
slides: {
perView: 3,
spacing: 8
}
}
}
},
[ThumbnailPlugin(instanceRef)]
)

return (
<>
<div ref={sliderRef} className='keen-slider'>
<div className='flex keen-slider__slide'>
<img src='/images/banners/1.jpg' alt='swiper 1' />
</div>
<div className='flex keen-slider__slide'>
<img src='/images/banners/2.jpg' alt='swiper 2' />
</div>
<div className='flex keen-slider__slide'>
<img src='/images/banners/3.jpg' alt='swiper 3' />
</div>
<div className='flex keen-slider__slide'>
<img src='/images/banners/4.jpg' alt='swiper 4' />
</div>
<div className='flex keen-slider__slide'>
<img src='/images/banners/5.jpg' alt='swiper 5' />
</div>
</div>

<div ref={thumbnailRef} className='mbs-4 keen-slider thumbnail'>
<div className='keen-slider__slide cursor-pointer'>
<img src='/images/banners/1.jpg' alt='swiper 1' />
</div>
<div className='keen-slider__slide cursor-pointer'>
<img src='/images/banners/2.jpg' alt='swiper 2' />
</div>
<div className='keen-slider__slide cursor-pointer'>
<img src='/images/banners/3.jpg' alt='swiper 3' />
</div>
<div className='keen-slider__slide cursor-pointer'>
<img src='/images/banners/4.jpg' alt='swiper 4' />
</div>
<div className='keen-slider__slide cursor-pointer'>
<img src='/images/banners/5.jpg' alt='swiper 5' />
</div>
</div>
</>
)
}

export default SwiperThumbnails
Fader
slider 0
slider 1
slider 2
slider 3
slider 4

// React Imports
import { useState } from 'react'

// MUI Imports
import Box from '@mui/material/Box'

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'

const images = [
'/images/banners/9.jpg',
'/images/banners/7.jpg',
'/images/banners/6.jpg',
'/images/banners/10.jpg',
'/images/banners/8.jpg'
]

const SwiperFader = () => {
// States
const [opacities, setOpacities] = useState<number[]>([])

// Hooks
const [sliderRef] = useKeenSlider<HTMLDivElement>({
slides: images.length,
detailsChanged(s) {
const new_opacities = s.track.details.slides.map(slide => slide.portion)

setOpacities(new_opacities)
}
})

return (
<div ref={sliderRef} className='fader md:bs-[395px] sm:bs-[250px] bs-[200px]'>
{images.map((src, idx) => (
<Box key={idx} className='fader__slide' sx={{ opacity: opacities[idx] }}>
<img src={src} alt={`slider ${idx}`} />
</Box>
))}
</div>
)
}

export default SwiperFader
Zoom
slider 0
slider 1
slider 2
slider 3
slider 4

// React Imports
import { useState } from 'react'

// MUI Imports
import Box from '@mui/material/Box'
import { useTheme } from '@mui/material/styles'

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'
import type { TrackDetails } from 'keen-slider/react'

const images = [
'/images/banners/6.jpg',
'/images/banners/7.jpg',
'/images/banners/8.jpg',
'/images/banners/9.jpg',
'/images/banners/10.jpg'
]

const SwiperZoom = () => {
// States
const [details, setDetails] = useState<TrackDetails | null>(null)

// Hooks
const [sliderRef] = useKeenSlider<HTMLDivElement>({
initial: 2,
detailsChanged(s) {
setDetails(s.track.details)
}
})

const scaleStyle = (idx: number) => {
if (!details) return {}
const slide = details.slides[idx]
const scale_size = 1
const scale = 1 - (scale_size - scale_size * slide.portion)

return {
transform: `scale(${scale})`,
WebkitTransform: `scale(${scale})`
}
}
const theme = useTheme()

return (
<div ref={sliderRef} className='keen-slider zoom-out md:bs-[395px] sm:bs-[250px] bs-[200px]'>
{images.map((src, idx) => (
<div key={idx} className='keen-slider__slide zoom-out__slide'>
<Box className='slider-content-wrapper' sx={{ ...scaleStyle(idx) }}>
<img src={src} alt={`slider ${idx}`} />
</Box>
</div>
))}
</div>
)
}

export default SwiperZoom
Auto Switch
swiper 1
swiper 2
swiper 3
swiper 4
swiper 5

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'

const SwiperAutoSwitch = () => {
// Hooks
const [ref] = useKeenSlider<HTMLDivElement>(
{
loop: true
},
[
slider => {
let mouseOver = false
let timeout: number | ReturnType<typeof setTimeout>
const clearNextTimeout = () => {
clearTimeout(timeout as number)
}
const nextTimeout = () => {
clearTimeout(timeout as number)
if (mouseOver) return
timeout = setTimeout(() => {
slider.next()
}, 2000)
}

slider.on('created', () => {
slider.container.addEventListener('mouseover', () => {
mouseOver = true
clearNextTimeout()
})
slider.container.addEventListener('mouseout', () => {
mouseOver = false
nextTimeout()
})
nextTimeout()
})
slider.on('dragStarted', clearNextTimeout)
slider.on('animationEnded', nextTimeout)
slider.on('updated', nextTimeout)
}
]
)

return (
<div ref={ref} className='keen-slider'>
<div className='keen-slider__slide'>
<img src='/images/banners/1.jpg' alt='swiper 1' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/2.jpg' alt='swiper 2' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/3.jpg' alt='swiper 3' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/4.jpg' alt='swiper 4' />
</div>
<div className='keen-slider__slide'>
<img src='/images/banners/5.jpg' alt='swiper 5' />
</div>
</div>
)
}

export default SwiperAutoSwitch
Mutation Observer

1


// React Imports
import { useState } from 'react'

// MUI Imports
import Button from '@mui/material/Button'
import { useTheme } from '@mui/material/styles'
import Typography from '@mui/material/Typography'

// Third-party Components
import { useKeenSlider } from 'keen-slider/react'
import type { KeenSliderPlugin } from 'keen-slider/react'

const MutationPlugin: KeenSliderPlugin = slider => {
const observer = new MutationObserver(mutations => {
mutations.forEach(() => {
slider.update()
})
})
const config = { childList: true }

slider.on('created', () => {
observer.observe(slider.container, config)
})
slider.on('destroyed', () => {
observer.disconnect()
})
}

const SwiperMutationObserver = () => {
// States
const [slides, setSlides] = useState<number[]>([1])

// Hooks
const theme = useTheme()
const [ref] = useKeenSlider<HTMLDivElement>(
{
slides: {
perView: 3,
spacing: 16
},
breakpoints: {
[`(max-width: ${theme.breakpoints.values.sm}px)`]: {
slides: { perView: 1, spacing: 16 }
}
}
},
[MutationPlugin]
)

return (
<>
<div ref={ref} className='keen-slider'>
{slides.map(slide => {
return (
<div key={slide} className='keen-slider__slide default-slide'>
<Typography variant='h1'>{slide}</Typography>
</div>
)
})}
</div>
<div className='flex mbs-4 gap-4'>
<Button variant='contained' onClick={() => setSlides([...slides, slides.length + 1])}>
Add
</Button>
<Button variant='contained' color='error' onClick={() => setSlides(slides.slice(0, -1))}>
Remove
</Button>
</div>
</>
)
}

export default SwiperMutationObserver