Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nuxt3 Swiper hydration issue #6634

Closed
5 of 6 tasks
JulianMar opened this issue Apr 28, 2023 · 7 comments
Closed
5 of 6 tasks

Nuxt3 Swiper hydration issue #6634

JulianMar opened this issue Apr 28, 2023 · 7 comments

Comments

@JulianMar
Copy link

JulianMar commented Apr 28, 2023

Check that this is really a bug

  • I confirm

Reproduction link

https://stackblitz.com/edit/nuxt-starter-y6fay4

Bug description

Ther's a hydration issue with a very simple implementation of the swiper in nuxt 3.
Check the console for the error

[vue warn]: Hydration children mismatch in <swiper-container>: server rendered element contains more child nodes than client vdom. 
  at <App key=3 > 
  at <NuxtRoot>

and

hydration completed but contains mismatches.

I know it's a framework specific error but imo it makes more sense to place it here. If I should post first in the nuxt issues, I will do that.

Expected Behavior

No response

Actual Behavior

No response

Swiper version

9.2.4

Platform/Target and Browser Versions

nuxt 3

Validations

  • Follow our Code of Conduct
  • Read the docs.
  • Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
  • 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
@JulianMar
Copy link
Author

The same issue happens in next.js aswell. So it's not framework related.

https://stackblitz.com/edit/nextjs-k3yjfv?file=pages/index.js

@JulianMar
Copy link
Author

hmmm this might be a deeper issue around vue and the compatibility of web components.
vuejs/core#8110

@alexovn
Copy link

alexovn commented May 1, 2023

Hello. I had the same problem and I found a solution. You need to add attribute init="false" to swiper-container, then initialize slider in mounted hook. Check this section: https://swiperjs.com/element#parameters-as-props

@JulianMar
Copy link
Author

That doesn't seem like a fix and more like a workaround to me. I will try it anyways. Thanks for the suggestion!

@StefanFlaschko
Copy link

StefanFlaschko commented Oct 6, 2023

@alexovn : How to initialize, could you share the code please?
I recognized that I only have the hydration mismatch when I'm using the 'nuxt-delay-hydration' module.

@alexovn
Copy link

alexovn commented Oct 12, 2023

@alexovn : How to initialize, could you share the code please? I recognized that I only have the hydration mismatch when I'm using the 'nuxt-delay-hydration' module.

Okey. You have several ways how to deal with it. First approach, just to use all swiper params and methods in the template. It seems that it works well now. Just check swiper docu. Second approach, do swiper init in onMounted hook:

*** NUXT 3 ***

<script setup>
  import { register } from 'swiper/element'

  const slider = ref()
  const showPrevBtn = ref(false)
  const showNextBtn = ref(false)

  register()

  const onSliderInit = (e) => {
    const [swiper] = e.detail

    showPrevBtn.value = !swiper.isBeginning
    showNextBtn.value = !swiper.isEnd
  }

  const slidePrev = () => {
    slider.value?.swiper.slidePrev()
  }

  const slideNext = () => {
    slider.value?.swiper.slideNext()
  }

  onMounted(async () => {
    const params = {
      slidesPerView: 'auto',
      on: {
        slideChange () {
          console.log('slide changed')
        },
      },
    }

    /**
      use nextTick() if you have swiper in <ClientOnly> component,
      'cause there will be no ref onMounted hook and
      you need to wait DOM update at first
    */
    await nextTick(() => {
      Object.assign(slider.value, params)
      slider.value.initialize()
    })
  })
</script>

<template>
  <div>
    <button
      :class="{ 'opacity-100 !visible': showPrevBtn }"
      type="button"
      aria-label="slide left"
      @click="slidePrev">
      Arrow Left
    </button>

    <ClientOnly>
      <template #fallback>
        Loading...
      </template>
      <swiper-container
        ref="slider"
        init="false"
        @init="onSliderInit">
        <swiper-slide
          v-for="(category, idx) in categories"
          :key="idx">
          <NuxtLink
            :to="`/catalog/${category.slug}`">
            <div>
              {{ category.name }}
            </div>
          </NuxtLink>
        </swiper-slide>
      </swiper-container>
    </ClientOnly>

    <button
      :class="{ 'opacity-100 !visible': showNextBtn }"
      type="button"
      aria-label="slide right"
      @click="slideNext">
      Arrow Right
    </button>
  </div>
</template>

@stijns96
Copy link

stijns96 commented Nov 7, 2023

Simply add the components to nuxt.config.ts.

export default defineNuxtConfig({
  vue: {
    compilerOptions: {
      isCustomElement: (tag) => tag.startsWith('swiper-'),
    },
  },
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants