swiper icon indicating copy to clipboard operation
swiper copied to clipboard

Weird behavior of Swiper.js in Next.js 13 & 14

Open isrezaei opened this issue 1 year ago • 11 comments

Check that this is really a bug

  • [x] I confirm

Reproduction link


Bug description

I don't know why I'm experiencing this behavior when I use Swiper in Next.js! Before the initial client-side rendering (SSR mode), I get an unstable Swiper style, as seen in these images. I don't know how to fix this on the first initial mount on every refresh.

bulshit behavior issue

Expected Behavior

"I don't want to see the flickering issue at the first refresh. It's not normal."

Actual Behavior

No response

Swiper version

11.1.4

Platform/Target and Browser Versions

chrome lasteat version

Validations

  • [X] Follow our Code of Conduct
  • [X] Read the docs.
  • [X] Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
  • [X] Make sure this is a Swiper issue and not a framework-specific issue

Would you like to open a PR for this bug?

  • [ ] I'm willing to open a PR

isrezaei avatar Jun 18 '24 12:06 isrezaei

Adding the cdn swiper files in document.tsx, helped me resolve this issue:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"
/>

<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>

JyotiRSharma avatar Jun 24 '24 18:06 JyotiRSharma

Nuxt 3 same problem

Wilson2254 avatar Aug 15 '24 14:08 Wilson2254

same problem

goswamikaushik001 avatar Aug 23 '24 06:08 goswamikaushik001

The flicker appears to stem from Swiper setting each slide's width/height after hydration, but not before on the server.

A solution to consider would be swiper offering some way to manually handle element height/width so we can seamlessly preserve the values from the server to the client.

dan-hale avatar Sep 05 '24 20:09 dan-hale

Adding the cdn swiper files in document.tsx, helped me resolve this issue:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"
/>

<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>

I use app router from nextjs 14, placed it like this, but it does not solve the problem...

const RootLayout: React.FC<Props> = ({ children }) => {
  return (
    <html>
      <head>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
        <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
      </head>
      <body>
               {children}
      </body>
    </html>
  )
}

Wimmind avatar Sep 18 '24 10:09 Wimmind

Adding the cdn swiper files in document.tsx, helped me resolve this issue:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"
/>

<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>

I use app router from nextjs 14, placed it like this, but it does not solve the problem...

const RootLayout: React.FC<Props> = ({ children }) => {
  return (
    <html>
      <head>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
        <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
      </head>
      <body>
               {children}
      </body>
    </html>
  )
}

I guess you need to use the hijacked script from Next check this out https://nextjs.org/docs/app/building-your-application/optimizing/scripts#application-scripts

Edit: this is for app router

JyotiRSharma avatar Sep 20 '24 13:09 JyotiRSharma

Adding the cdn swiper files in document.tsx, helped me resolve this issue:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"
/>

<script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>

I use app router from nextjs 14, placed it like this, but it does not solve the problem...

const RootLayout: React.FC<Props> = ({ children }) => {
  return (
    <html>
      <head>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css" />
        <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
      </head>
      <body>
               {children}
      </body>
    </html>
  )
}

I guess you need to use the hijacked script from Next check this out https://nextjs.org/docs/app/building-your-application/optimizing/scripts#application-scripts

Edit: this is for app router

I tried, thanks, but it didn't help unfortunately...

Wimmind avatar Sep 23 '24 17:09 Wimmind

@isrezaei The issue arises because Swiper calculates and assigns each slide's width and margin only after the JavaScript loads. This can cause layout shifts, especially in server-side rendering (SSR) environments where initial styles are applied inconsistently.

To prevent this, a workaround could involve pre-setting the slide widths and margins in CSS based on the expected layout, so the layout is more stable before Swiper's JavaScript adjusts the slides. Additionally, if the layout shifts are too significant, consider implementing a custom solution to handle these styles on the server side.

mahmoudAcm avatar Oct 29 '24 17:10 mahmoudAcm

livr.net/npm/swiper@11/swiper-bundle.min.js">

Do you have any working solution for that?

kousikdas02 avatar Oct 31 '24 06:10 kousikdas02

same issue here

niazyeladawyalt avatar Jan 27 '25 11:01 niazyeladawyalt

FWIW, I tried a hacky solution by adding margin-left to the swiperslide and it seems to be working fine for now.

<Swiper slidesPerView="auto" freeMode={true} modules={[FreeMode]}>
  {cards.map((card, index) => (
    <SwiperSlide
      key={index}
      style={{ 
        width: "auto",
        marginLeft: index === 0 ? '0px' : '16px',
       }}
    >
      {card}
    </SwiperSlide>
  ))}
</Swiper>

Hopefully, someone can provide an actual solution

yunchanpaik avatar Jan 31 '25 06:01 yunchanpaik