swiper
swiper copied to clipboard
Using breakpoints option in Next JS causes Hydration error
Discussed in https://github.com/nolimits4web/swiper/discussions/5776
Originally posted by Sakkhor909 June 7, 2022 First of all, thank you for this amazing library.
Everything works fine until I use breakpoints
import { Swiper, SwiperSlide } from "swiper/react";
import Image from "next/image";
<Swiper
slidesPerView={1}
breakpoints={{
1024: {
slidesPerView: 3,
},
}}
>
{Data.images.map((imgSrc, index) => {
return (
<SwiperSlide>
<Image src={imgSrc} alt={Data.name + index} layout="fill" />
</SwiperSlide>
);
})}
</Swiper>
The error is shown on the next js page
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Than same issue with me also
Same here
I am also facing the same issue.
Same issue
Using slidesPerView="auto" fixed the issue for me.
Sample Code for reference
<Swiper
spaceBetween={10}
slidesPerView="auto"
breakpoints={{
320: {
slidesPerView: 1,
spaceBetween: 30,
},
640: {
slidesPerView: 1,
spaceBetween: 10,
},
768: {
slidesPerView: 2,
spaceBetween: 20,
},
1024: {
slidesPerView: 3,
spaceBetween: 30,
},
}}
>
<SwiperSlide>Slide one</SwiperSlide>
</Swiper>
This actually makes sense. Your static build created the HTML without a screensize, so the default settings are run. When your JS runs for the first time, it will consider breakpoints, thus creating a mismatch in HTML elements.
Using
slidesPerView="auto"fixed the issue for me.Sample Code for reference
<Swiper spaceBetween={10} slidesPerView="auto" breakpoints={{ 320: { slidesPerView: 1, spaceBetween: 30, }, 640: { slidesPerView: 1, spaceBetween: 10, }, 768: { slidesPerView: 2, spaceBetween: 20, }, 1024: { slidesPerView: 3, spaceBetween: 30, }, }} > <SwiperSlide>Slide one</SwiperSlide> </Swiper>
Thank you for the solution. It works.
Using
slidesPerView="auto"fixed the issue for me. Sample Code for reference<Swiper spaceBetween={10} slidesPerView="auto" breakpoints={{ 320: { slidesPerView: 1, spaceBetween: 30, }, 640: { slidesPerView: 1, spaceBetween: 10, }, 768: { slidesPerView: 2, spaceBetween: 20, }, 1024: { slidesPerView: 3, spaceBetween: 30, }, }} > <SwiperSlide>Slide one</SwiperSlide> </Swiper>Thank you for the solution. It works.
I want to have a bit of the next slide peaking on the screen, so slidesPerView=auto won't work for me- any other ideas or possible fixes you came up with?
At the moment, No
<div className="relative w-full lg:mx-auto lg:max-w-7xl">
<Swiper
slidesPerView={3}
spaceBetween={20}
breakpoints={{
768: {
slidesPerView: 4,
spaceBetween: 20,
},
1024: {
slidesPerView: 5,
spaceBetween: 10,
},
1280: {
slidesPerView: 6,
},
1440: {
slidesPerView: 7,
},
}}
>
{[...Array(7).keys()].map((item) => (
<SwiperSlide key={item}>
Slide {item}
</SwiperSlide>
))}
</Swiper>
</div>
This is my solution. I have used Tailwind CSS, and wrapped Swiper with one more div, and gave width: 100%.
it works ok
Using
slidesPerView="auto"fixed the issue for me.Sample Code for reference
<Swiper spaceBetween={10} slidesPerView="auto" breakpoints={{ 320: { slidesPerView: 1, spaceBetween: 30, }, 640: { slidesPerView: 1, spaceBetween: 10, }, 768: { slidesPerView: 2, spaceBetween: 20, }, 1024: { slidesPerView: 3, spaceBetween: 30, }, }} > <SwiperSlide>Slide one</SwiperSlide> </Swiper>
Great Solution. Many thanks for giving your valuable time to fix it.
Just want to clarify here, slidesPerView="auto" is not a fix, it's a workaround.
slidesPerView="auto" also resolved my issue. thanks @iampawan31
If you decide to use slidesPerView="auto" you have to take into account that you have to control the CLS (Web Vitals) since doing this causes the images to move, in the first render they will be loaded automatically while in the next one it will exist a design change.
Using
slidesPerView="auto"fixed the issue for me.Sample Code for reference
<Swiper spaceBetween={10} slidesPerView="auto" breakpoints={{ 320: { slidesPerView: 1, spaceBetween: 30, }, 640: { slidesPerView: 1, spaceBetween: 10, }, 768: { slidesPerView: 2, spaceBetween: 20, }, 1024: { slidesPerView: 3, spaceBetween: 30, }, }} > <SwiperSlide>Slide one</SwiperSlide> </Swiper>
Thank you for the solution. It works.
Is anyone still getting hydration error even after using slidesperview ="auto" ?
<Swiper
spaceBetween={50}
slidesPerView="auto"
loopedSlides={3}
pagination={{
el: ".my-custom-pagination-div",
clickable: true,
renderBullet: (index, className) => {
return '<span class="' + className + '">' + "</span>";
},
}}
navigation={true}
loop={true}
centeredSlides={true}
breakpoints={{
992: {
slidesPerView: 2,
},
}}
onSlideChange={(swiperCore) => {
const { activeIndex, snapIndex, previousIndex, realIndex } =
swiperCore;
setActiveApp(realIndex);
}}
// left and right carousels should be half
// width of the slide
>
{data.map((item, index) => {
return (
<SwiperSlide key={index}>
<DataCard
visits={visits}
item={item}
active={activeData === index}
/>
</SwiperSlide>
);
})}
{isDesktop && (
<>
<PrevOverlay />
<NextOverlay />
</>
)}
</Swiper>
Is anyone still getting hydration error even after using slidesperview ="auto" ?
<Swiper spaceBetween={50} slidesPerView="auto" loopedSlides={3} pagination={{ el: ".my-custom-pagination-div", clickable: true, renderBullet: (index, className) => { return '<span class="' + className + '">' + "</span>"; }, }} navigation={true} loop={true} centeredSlides={true} breakpoints={{ 992: { slidesPerView: 2, }, }} onSlideChange={(swiperCore) => { const { activeIndex, snapIndex, previousIndex, realIndex } = swiperCore; setActiveApp(realIndex); }} // left and right carousels should be half // width of the slide > {data.map((item, index) => { return ( <SwiperSlide key={index}> <DataCard visits={visits} item={item} active={activeData === index} /> </SwiperSlide> ); })} {isDesktop && ( <> <PrevOverlay /> <NextOverlay /> </> )} </Swiper>
Yes
Is anyone still getting hydration error even after using slidesperview ="auto" ?
<Swiper spaceBetween={50} slidesPerView="auto" loopedSlides={3} pagination={{ el: ".my-custom-pagination-div", clickable: true, renderBullet: (index, className) => { return '<span class="' + className + '">' + "</span>"; }, }} navigation={true} loop={true} centeredSlides={true} breakpoints={{ 992: { slidesPerView: 2, }, }} onSlideChange={(swiperCore) => { const { activeIndex, snapIndex, previousIndex, realIndex } = swiperCore; setActiveApp(realIndex); }} // left and right carousels should be half // width of the slide > {data.map((item, index) => { return ( <SwiperSlide key={index}> <DataCard visits={visits} item={item} active={activeData === index} /> </SwiperSlide> ); })} {isDesktop && ( <> <PrevOverlay /> <NextOverlay /> </> )} </Swiper>
I had a similar situation, but solved it by limiting Swiper calls to client-side. It may be a bit of a messy solution.... ↓
const [isClient, setIsClient] = useState(false)
const createSwiper = () => {
if (isClient) {
return <SlideShowContainer />
} else {
<></>
}
}
useEffect(() => {
setIsClient(true)
}, [])
// use createSwiper()
const SwiperContainer = () => {
return {createSwiper()}
}
// Define Swiper
const SlideShowContainer = () => {
return (
<Swiper
.....>
</Swiper>
}
Using
slidesPerView="auto"fixed the issue for me.Sample Code for reference
<Swiper spaceBetween={10} slidesPerView="auto" breakpoints={{ 320: { slidesPerView: 1, spaceBetween: 30, }, 640: { slidesPerView: 1, spaceBetween: 10, }, 768: { slidesPerView: 2, spaceBetween: 20, }, 1024: { slidesPerView: 3, spaceBetween: 30, }, }} > <SwiperSlide>Slide one</SwiperSlide> </Swiper>
it does not worked for me .
the breakepoints section working with window object and its not accessible on Hydration .
so is there any solution?
I don't know is it dirty or not? but i fixed it by the code :
const [customSwiperOptions, setCustomSwiperOptions] = useState<SwiperOptions>();
useEffect(() => {
const options: SwiperOptions = {
breakpoints: {
320: {
slidesPerView: 1,
},
640: {
slidesPerView: 2,
},
768: {
slidesPerView: 3,
},
1024: {
slidesPerView: 4,
},
1280: {
slidesPerView: 5,
},
1536: {
slidesPerView: 6
}
}
}
setCustomSwiperOptions(options);
}, [])
{
customSwiperOptions &&
<Swiper modules={[Navigation, Pagination, Scrollbar, A11y]}
spaceBetween={20}
navigation
breakpoints={customSwiperOptions.breakpoints}
pagination={{ clickable: true }}
scrollbar={{ draggable: true }}>
{
myItems.map((x) => {
return <SwiperSlide key={x.id} className='p-2'> <Item data={x}></Item></SwiperSlide>
})
}
</Swiper>
}
Even if we keep swiper client side, isn't it causing a huge CLS ?
Using
slidesPerView="auto"fixed the issue for me.Sample Code for reference
<Swiper spaceBetween={10} slidesPerView="auto" breakpoints={{ 320: { slidesPerView: 1, spaceBetween: 30, }, 640: { slidesPerView: 1, spaceBetween: 10, }, 768: { slidesPerView: 2, spaceBetween: 20, }, 1024: { slidesPerView: 3, spaceBetween: 30, }, }} > <SwiperSlide>Slide one</SwiperSlide> </Swiper>
That works, Thanks!!
Thanks it worked for me. :)
I don't know is it dirty or not? but i fixed it by the code :
const [customSwiperOptions, setCustomSwiperOptions] = useState<SwiperOptions>(); useEffect(() => { const options: SwiperOptions = { breakpoints: { 320: { slidesPerView: 1, }, 640: { slidesPerView: 2, }, 768: { slidesPerView: 3, }, 1024: { slidesPerView: 4, }, 1280: { slidesPerView: 5, }, 1536: { slidesPerView: 6 } } } setCustomSwiperOptions(options); }, []) { customSwiperOptions && <Swiper modules={[Navigation, Pagination, Scrollbar, A11y]} spaceBetween={20} navigation breakpoints={customSwiperOptions.breakpoints} pagination={{ clickable: true }} scrollbar={{ draggable: true }}> { myItems.map((x) => { return <SwiperSlide key={x.id} className='p-2'> <Item data={x}></Item></SwiperSlide> }) } </Swiper> }
Thank you for this, I feel this is the best solution on this thread!
I made some small simplifications:
` const [customSwiperOptions, setCustomSwiperOptions] = useState(null);
useEffect(() => { const options = { 640: { slidesPerView: 2, spaceBetween: 20, }, 768: { slidesPerView: 2, spaceBetween: 20, }, 1024: { slidesPerView: 3, spaceBetween: 20, }, 1200: { slidesPerView: 4, spaceBetween: 20, }, } setCustomSwiperOptions(options); }, [])
const testimonialCarousel = { slidesPerView: 1, spaceBetween: 20, loop: true, speed: 1000, centeredSlides: true, autoHeight: true, modules: [Autoplay], autoplay: { waitForTransition: false, delay: 4000, }, breakpoints: customSwiperOptions };
{customSwiperOptions && <Swiper {...testimonialCarousel}
>
{TESTIMONIALS_DATA.map((item, index) => (
<SwiperSlide key={index}>
{item.map(({ image, text, name, username }, _index) => (
<TestimonialsCard
image={image}
text={text}
name={name}
key={_index}
username={username}
sx={styles.testimonialsCard}
/>
))}
</SwiperSlide>
))}
</Swiper>}`
this is nice