swiper: [swiper/react] Custom navigation/pagination components using React refs not working/possible?
- Swiper Version: 6.2.0
- Platform/Target and Browser Versions: All
Also posten on Stackoverflow: Swiper React | How to create custom navigation/pagination components using React refs?
What you did
const MySwiper = () => {
const navigationPrevRef = React.useRef(null)
const navigationNextRef = React.useRef(null)
return (
<Swiper
navigation={{
prevEl: navigationPrevRef.current,
nextEl: navigationNextRef.current,
}}
>
<SwiperSlide>slide 1</SwiperSlide>
<SwiperSlide>slide 2</SwiperSlide>
<div ref={navigationPrevRef} />
<div ref={navigationNextRef} />
</Swiper>
)
}
Expected Behavior
To work
Actual Behavior
Did not work
SwiperJS documentation states that navigation prevEl/nextEl can either be of type “string” or “HTMLElement”. Using HTML nodes allows for navigation prevEl/nextEl to be scoped to each rendered instance of MySwiper
. In React this is usually done with “refs”.
const App = () => (
<div>
<MySwiper /> // MySwiper1
<MySwiper /> // MySwiper2
</div>
)
In the App
example above, navigation prevEl/nextEl from “MySwiper2” should not trigger sliding of “MySwiper1”, which is what would happen if one would have used string selectors like { prevEl: '.prev', nextEl: '.next' }
. Obviously (if even possible within the application) one could generate unique classnames. A better solution would be to pass the HTML elements as these are already unique. Is this possible somehow with React refs?
My current 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>
)
}
Thanks in advance!
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 10
- Comments: 74 (1 by maintainers)
I was having a hard time getting some of the above examples to work. I ended up using the slidePrev() and slideNext() functions like this:
Another way to solve this problem:
Not possible by passing directly as
refs
are null initially, so it is possible with your approach or similar:In case this helps anyone using Swiper with TypeScript:
No need to define
navigation
/pagination
props on Swiper unless you need/want to override other things.@mistval this works, but you will lose the automatic state handling of the navigation buttons (css classes like .swiper-button-disabled etc).
I use this simple react hook to solve this:
and then use it like this:
you should be able to use this hook with everything ref related, for example with the pagination:
@danvisintainer sure:
Could anybody show me full code? (and if you could Typescript?) I’m strugging making this.
swiper.params.navigation.prevEl = prevRef.current;
inonInit
can be error:@rikusen0335 @nolimits4web I’d also appreciate some React/TypeScript help here:
The example below works, but only because of the
@ts-ignore
due to the type error in the comment above.TypeScript solution
With the previous solution, the buttons might not work. You need to tweak it a bit. Be sure to initialize the state with null:
None of these solutions worked for me except this one I found on stack overflow https://stackoverflow.com/questions/70324190/custom-arrow-swiper-slider-next-js-sass/74165878#74165878
I hope this helps someone!
Typescript solution
hey guys, 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:
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
@rikusen0335 I played around with this a bit more (still in TypeScript) and got the following to work for custom navigation, with refs (so as not to use
className
):This works for me, without having to call the
onInit
function and assign the params.Thank you so much, this acctualy help me solve my problem!!!
This works for me! Thank you very much, @coolzyte @chitalian
Typescript Solution without useState
simply this works for me without type error.
Don’t know if this still convenient but. I fixed this issue by import the Navigation module from swiper. and everything works as expected.
This works for me thank you
I’ve tried all the solutions above using Typescript and none worked, only this one worked for me.
try this
(swiper.params.navigation as NavigationOptions).prevEl = prevRef.current;
@kruzyk I only used Swiper once so I imagine other people might be able to inform better what is the right approach for this. I don’t know what you meant about
swiper-button-disabled
but see an example below if you want to disable the buttons once Swiper reached the beginning and end of the slides.This solution worked for me. Using React, typescript and swiper@6.8.4
I know it’s not perfect solution for typescript users, but if none of previous examples works for you, maybe this one will. I know that using “any” isn’t great, but it’s still better than ts-ignore.
P.S. Do not downvote me, it’s my first comment on github. Just say my solution sucks. 😄
@taze-fullstack you can try this
in swiper
“swiper”: “^8.2.6”
This works for me, thanks
This works for me
and then we could use it:
That`s how i create custom paginatipn container
`import { Swiper, SwiperSlide } from “swiper/react”; import s from “./Slider.module.css”; import { EffectFade, Pagination } from ‘swiper’; import “swiper/css”; import ‘swiper/css/pagination’; import React from “react”;
const Slider = () => { console.log(s); return ( <section className={s.slider}> <div className="wrapper"> <div className={s.sliderWrapper}> <Swiper className={s.sliderContiner} spaceBetween={0} autoHeight={true} slidesPerView={1} modules={[EffectFade, Pagination]} pagination={{ clickable: true, el :
.${s.paginationEl}
, bulletClass : s.paginationEl, bulletActiveClass : s.paginationBtnActive }} effect=“fade” > <SwiperSlide className={s.sliderSlide}> <div className={s.slideContainer}>01
Our team works with our partners on all aspects of project execution from origination through disposition, providing investors with expeditious access to well-established and well-run projects that often have long track records of success.
</div> </SwiperSlide> <SwiperSlide className={s.sliderSlide}> <div className={s.slideContainer}>02
Our team works with our partners on all aspects of project execution from origination through disposition, providing investors with expeditious access to well-established and well-run projects that often have long track records of success. Our team works with our partners on all aspects of project execution from origination through disposition, providing investors with expeditious access to well-established and well-run projects that often have long track records of success.
</div> </SwiperSlide> <SwiperSlide className={s.sliderSlide}> <div className={s.slideContainer}>03
Our team works with our partners on all aspects of project execution from origination through disposition, providing investors with expeditious access to well-established and well-run projects that often have long track records of success.
</div> </SwiperSlide> </Swiper> <div className={s.paginationEl}></div> </div> </div> </section> ); };export default Slider;`
and my styles:
`.paginationEl{
}
.paginationBtn{ width: 20px; height: 20px; }
.paginationBtnActive{
}`
It’s far from developer friendly, these bypass techniques should be default to swiper.js…
I had to make some modifications to make it work, im new to TS so open to feedback
Worked for me Thanks
Thanks! This is working well. Simplest cleanest solution here.
@markcnunes nice, but what about dynamic changes like adding
swiper-button-disabled
? I tried on 8.3.1 and this seems to not work…As mentioned by Muskos on https://github.com/nolimits4web/swiper/issues/3855#issuecomment-10722631 it is now possible to use
useSwiper
to generate a custom navigation.And the pagination can be customized via the Swiper configuration - https://swiperjs.com/demos#pagination-custom
Work for me…
In a new version of slider you can use hook https://swiperjs.com/react#use-swiper
In case someone stumbles here:
@michaelthorne solution works for me, the solution from @ddtch looked very good in the beginning, but the navigation buttons are sometimes not triggering. Dont know why, maybe its the compination with SSR / next.js / next/image (lazy loading images in slides).
@michaelthorne Thank you for your code. I did exact same way because there’s only way to cast to any it or, just @ts-ignore.
thank you you saved me @maeertin 🙏
This is quite straight forward. Thanks for sharing!
The above schemes have type errors in the default
typescript
project created by CRA and cannot be used. The following is an exampleswiper@6.8.4
Workarounds available in version typescript.Ohh that’s pretty nice code writing. Thank you for your advise, I really appreciate it.