swiper icon indicating copy to clipboard operation
swiper copied to clipboard

Using breakpoints option in Next JS causes Hydration error

Open Sakkhor909 opened this issue 3 years ago • 13 comments

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.

Sakkhor909 avatar Jun 08 '22 18:06 Sakkhor909

Than same issue with me also

AbdushukurRasulov avatar Jun 12 '22 20:06 AbdushukurRasulov

Same here

Jared0430 avatar Jun 15 '22 18:06 Jared0430

I am also facing the same issue.

iampawan31 avatar Jun 15 '22 20:06 iampawan31

Same issue

ssandlan avatar Jun 16 '22 11:06 ssandlan

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>

iampawan31 avatar Jun 16 '22 15:06 iampawan31

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.

laurenskling avatar Jun 23 '22 09:06 laurenskling

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.

Sakkhor909 avatar Jun 26 '22 11:06 Sakkhor909

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?

jordanlambrecht avatar Jul 07 '22 19:07 jordanlambrecht

At the moment, No

Sakkhor909 avatar Jul 12 '22 06:07 Sakkhor909

<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

AbdushukurRasulov avatar Jul 12 '22 06:07 AbdushukurRasulov

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.

alimasha-design avatar Jul 25 '22 15:07 alimasha-design

Just want to clarify here, slidesPerView="auto" is not a fix, it's a workaround.

laurenskling avatar Jul 25 '22 18:07 laurenskling

slidesPerView="auto" also resolved my issue. thanks @iampawan31

moinulmoin avatar Aug 18 '22 11:08 moinulmoin

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.

vicasas avatar Oct 10 '22 14:10 vicasas

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.

MuharremGonel avatar Oct 26 '22 23:10 MuharremGonel

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>

sandrinjoy avatar Oct 28 '22 03:10 sandrinjoy

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

jakeprins avatar Nov 01 '22 19:11 jakeprins

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>
}

kentakunkentakun avatar Nov 12 '22 08:11 kentakunkentakun

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?

Helius01 avatar Nov 13 '22 13:11 Helius01

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>
}

Helius01 avatar Nov 13 '22 14:11 Helius01

Even if we keep swiper client side, isn't it causing a huge CLS ?

sandrinjoy avatar Nov 13 '22 14:11 sandrinjoy

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!!

pieeee avatar Nov 22 '22 18:11 pieeee

Thanks it worked for me. :)

ajmaurya99 avatar Dec 09 '22 14:12 ajmaurya99

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>}`

kaidezen avatar Dec 24 '22 19:12 kaidezen

this is nice

bandesha101 avatar Jun 15 '23 10:06 bandesha101