'Swiper React | How to create custom navigation/pagination components using React refs?
SwiperJS documentation states that navigation prevEl/nextEl can either be of type "string" or "HTMLElement". Using string selectors is easy enough as:
const MySwiper = (props) => (
<Swiper
navigation={{
prevEl: '.prev',
nextEl: '.next',
}}
{...props}
>
<SwiperSlide>slide 1</SwiperSlide>
<SwiperSlide>slide 2</SwiperSlide>
<div className="prev" />
<div className="next" />
</Swiper>
)
However, how would this be correctly implemented with React refs? Using HTML nodes instead of string selectors allows for navigation prevEl/nextEl to be scoped to each rendered instance of MySwiper.
const App = () => (
<div>
<MySwiper className="mySwiper1" />
<MySwiper className="mySwiper2" />
</div>
)
In the App example above, navigation prevEl/nextEl from .mySwiper2 should not trigger sliding of .mySwiper1, which is what would happen with string selectors.
My current sad & hacky workaround:
const MySwiper = () => {
const navigationPrevRef = React.useRef(null)
const navigationNextRef = React.useRef(null)
return (
<Swiper
navigation={{
// Both prevEl & nextEl are null at render so this does not work
prevEl: navigationPrevRef.current,
nextEl: navigationNextRef.current,
}}
onSwiper={(swiper) => {
// Delay execution for the refs to be defined
setTimeout(() => {
// Override prevEl & nextEl now that refs are defined
swiper.params.navigation.prevEl = navigationPrevRef.current
swiper.params.navigation.nextEl = navigationNextRef.current
// Re-init navigation
swiper.navigation.destroy()
swiper.navigation.init()
swiper.navigation.update()
})
}}
>
<SwiperSlide>slide 1</SwiperSlide>
<SwiperSlide>slide 2</SwiperSlide>
<div ref={navigationPrevRef} />
<div ref={navigationNextRef} />
</Swiper>
)
}
Solution 1:[1]
I think I fixed the issue, I also faced the same problem, but finally, let's start
1. import SwiperCore, { Navigation} from 'swiper'
2. SwiperCore.use([Navigation])
3. i will use your exmaple:
const MySwiper = () => {
const navigationPrevRef = React.useRef(null)
const navigationNextRef = React.useRef(null)
return (
<Swiper
navigation={{
prevEl: navigationPrevRef.current,
nextEl: navigationNextRef.current,
}}
onBeforeInit={{
swiper.params.navigation.prevEl = navigationPrevRef.current;
swiper.params.navigation.nextEl = navigationNextRef.current;
}}
>
<SwiperSlide>slide 1</SwiperSlide>
<SwiperSlide>slide 2</SwiperSlide>
<div ref={navigationPrevRef} />
<div ref={navigationNextRef} />
</Swiper>
)
}
that's it, so if you check Swiper duc there is a page only for API, where you can find a section talking about events that swiper provide, anyway i hope this was helpful
Solution 2:[2]
just watch out for a little mistake with onBeforeInit into sample of Amine D.
corrected code:
const MySwiper = () => {
const navigationPrevRef = React.useRef(null)
const navigationNextRef = React.useRef(null)
return (
<Swiper
navigation={{
prevEl: navigationPrevRef.current,
nextEl: navigationNextRef.current,
}}
onBeforeInit={(swiper) => {
swiper.params.navigation.prevEl = navigationPrevRef.current;
swiper.params.navigation.nextEl = navigationNextRef.current;
}}
>
<SwiperSlide>slide 1</SwiperSlide>
<SwiperSlide>slide 2</SwiperSlide>
<div ref={navigationPrevRef} />
<div ref={navigationNextRef} />
</Swiper>
)
}
Solution 3:[3]
Passing refs directly is apparently not possible in Swiper v6.2.0.
I created a Github issue as well for anyone ending up here where the library author answered. https://github.com/nolimits4web/swiper/issues/3855
Solution 4:[4]
While Pierrat's answer did initially solve it for me, I was encountering a bug where the navigation buttons wouldn't do anything until after I'd paused and restarted the Swiper.
To fix, I created my own functions for handling the updates and used those instead.
const MyComponent = () => {
const sliderRef = useRef(null);
const handlePrev = useCallback(() => {
if (!sliderRef.current) return;
sliderRef.current.swiper.slidePrev();
}, []);
const handleNext = useCallback(() => {
if (!sliderRef.current) return;
sliderRef.current.swiper.slideNext();
}, []);
return (
<div>
<Swiper ref={sliderRef}>
<SwiperSlide />
...slides
<SwiperSlide />
</Swiper>
<div className="prev-arrow" onClick={handlePrev} />
<div className="next-arrow" onClick={handleNext} />
</div>
)
}
Solution 5:[5]
As per the previous answers, the following one is the complete code. That may help you to implement as you want.
import React from "react";
import SwiperCore, { Navigation } from 'swiper';
import { Swiper, SwiperSlide } from "swiper/react";
SwiperCore.use([Navigation]);
const MySwiper = () => {
const navigationPrevRef = React.useRef(null)
const navigationNextRef = React.useRef(null)
return (
<Swiper
navigation={{
prevEl: navigationPrevRef.current,
nextEl: navigationNextRef.current,
}}
setTimeout(() => {
// Override prevEl & nextEl now that refs are defined
swiper.params.navigation.prevEl = navigationPrevRef.current
swiper.params.navigation.nextEl = navigationNextRef.current
// Re-init navigation
swiper.navigation.destroy()
swiper.navigation.init()
swiper.navigation.update()
})
>
<SwiperSlide>slide 1</SwiperSlide>
<SwiperSlide>slide 2</SwiperSlide>
<div ref={navigationPrevRef} />
<div ref={navigationNextRef} />
</Swiper>
)
}
const App = () => (
<div>
<MySwiper className="mySwiper1" />
<MySwiper className="mySwiper2" />
</div>
)
ReactDOM.render(<App/>, document.getElementById('root'));
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Amine D |
| Solution 2 | pierrat.dev |
| Solution 3 | maeertin |
| Solution 4 | James Hooper |
| Solution 5 |
