nuxt-swiper
nuxt-swiper copied to clipboard
🚨⚠️ Important Announcement ⚠️🚨
Update 11-29-2023
Please test and try out the new swiper element release.
[!NOTE] This is still a work in progress as the api and helper compostables might change.
# npm
npm install nuxt-swiper@next
# yarn
yarn add nuxt-swiper@next
#pnpm
pnpm add nuxt-swiper@next
#bun
bun add nuxt-swiper@next

Moving forward Swiper.js is moving to web components. Removing support for Vue/React libraries in favor of web components. This means that nuxt-swiper
will be obsolete in the coming months for the swiper/vue
package. This means that if you see any bugs within the swiper/vue modules it's most likely it will not be fixed 🙁
So what does this mean?
Well this means that I will have to a totally re-write to support swiper/elements
, Which in this case -- I really don't know if there is really any benefit of doing so when you can just import the element straight to your project to work out of the box. When creating nuxt-swiper
I wanted to make it easier setting up swiper.js for my various personal projects and it worked for what I needed.
In the recent months I have been receiving issues that are non related to nuxt-swiper
itself, as it makes swiper.js easier to work with all the great things Nuxt provides which is Auto Imports, Typescript types and the plug n' play module system it has. I've have been trying to help many people with there problems but some are just beyond my capabilities to fix since I do not maintain the swiper/core.
So I would love to discuss potentially implementing swiper/elements but I would love to talk to the community to see if it something that is even feasible to do. I appreciate everyone that has supported and starred the project! It means the world! Please feel free to discuss what you think below.
Links:
Thanks, CP 💚
I have no experience with Web Components, but what happens to TypeScript, do we go back to vanilla JavaScript when interacting with these?
Does it mean, we need also need go back to manually importing, every Module/CSS file that we want, explicitly?
Thanks for sharing.
@FranciscoKloganB
Hey 👋! I will have to look into as I never worked with web components with Typescript but I think it's possible still but I just have to see how it works. I will let you know.
Technically yes but I could re-write the package to include the web components in this package so you wouldn't have to import manually. I just have to figure it out if it's even useful for everyone to make the change!
Thanks, CP
@cpreston321
Should we leave nuxt-swiper on the stable version of Swiper 8 which will still support Vue components or start a new branch with a module that will work with the new Swiper and will also provide a wrapper for the WebComponents?
I do not know what it is, but from the example code looks like the same as the usual components
Hey @NnicanBuak!
I think the current version of Swiper 9 is best bet to keep bugs limited but knowing we are going to lose support for the main package will come will drawbacks including bugs which I don't control. I think we can keep it on Swiper 9 until compatibility is lost.
I do think it's feasible to do a major version bump to then support elements out of the box. I am going to look more into it to see if there is a way implement typescript types. If so that might be the best route.
I can try to gather as much information as I can, but I mostly a backend developer playing "the frontend world". 😅
If I find relevant information, I will share it here.
Have not been able to figure out much but here are the things that are "obvious" after trying to migrate from this package to web-components
solution. There is way more boilerplate involved. Somethings about the web-components
API appear a bit less straightforward.
Here is a list of a few things I had to do.
- Like in "vanilla" Swiper, we must load styles for desired modules explicitly. However, there is a caveat, they must be injected globally and also a value to
injectStylesUrls
key inSwiperOptions
. The only way I found to do this was to create an array that pulled Swiper module styles I have interest in containing strings pointing tocdn.jsdelivr.net
, passing them touseHead
and also to<swiper-container>
. - Must pre-render
swiper-container
on the server, otherwise,onMounted
hook does not findswiper-container
when doing thequerySelector
invocation when Hydrating on the client.- Optionally render a dummy
swiper-slide
on the server to avoid content shift later.
- Optionally render a dummy
- Must add the property
<swiper-container :init="false" />
to prevent swiper initialization until parameters are merged (this approach is required whenever we usebreakpoints
or addmodules
to theSwiperOptions
object.- To merge the parameters an
onMounted
hook routine is required, to find theswiper-container
HTML element and merge ourSwiperObjects
with it. - We can now call the queried element
initialize
function. At this point Swiper starts working more or less like before.-
issue: the function
initialize
is not recognized byTypeScript
so we need to declare a union type or useany
:cry:
-
issue: the function
- To merge the parameters an
- Must call
register
(only once - still need to figure out the best place to do this) - Typescript not fully supported at the WebComponent level (e.g., within the we get
(property) SwiperSlide: any
)
The code snippets below are only a fraction of the pain I had to go truth to migrate my carousel (which was rather "simple") to web-components (and I am still losing my scrollbar and pagination components when going from small screens to big screens).
// nuxt.config.ts
/**
* @see https://vuejs.org/guide/extras/web-components.html#using-custom-elements-in-vue
* @see https://nuxt.com/docs/api/configuration/nuxt-config#compileroptions-1
*/
vue: {
compilerOptions: {
isCustomElement: (tag: string) =>
['swiper-container', 'swiper-slide'].includes(tag),
},
},
// composables/useSwiper.ts
export function useSwiper(
options: SwiperOptions,
moduleStylesUrls: Readonly<string[]> = []
) {
const swiperContainerRef = ref<HTMLElement>()
register()
useHead({
link: moduleStylesUrls.map((url) => ({
href: url,
rel: 'stylesheet',
type: 'text/css',
})),
})
onMounted(() => {
/**
* @see https://swiperjs.com/element#core-version-and-modules
* @see https://swiperjs.com/element#parameters-as-props
*/
if (swiperContainerRef.value) {
const swiperContainerEl = swiperContainerRef.value as HTMLElement & {
initialize: () => void
}
Object.assign(swiperContainerEl, options)
swiperContainerEl.initialize()
} else {
throw createError({
message: `Could not create carousel. Missing DOM element <swiper-container />.`,
statusCode: 500,
statusMessage: `Internal Server Error`,
})
}
})
return swiperContainerRef
}
// components/HomeCarousel.vue
<script>
const swiperStylesCdnUrl = [
'https://cdn.jsdelivr.net/npm/[email protected]/modules/autoplay/autoplay.min.css',
'https://cdn.jsdelivr.net/npm/[email protected]/modules/pagination/pagination.min.css',
'https://cdn.jsdelivr.net/npm/[email protected]/modules/scrollbar/scrollbar.min.css',
] as const
const paginationEnabled = ref(true)
const scrollbarEnabled = ref(true)
const swiperOptions = reactive<SwiperOptions>({
...otherSwiperOptionsNotReallyRelevantForTheExample,
injectStylesUrls: [...swiperStylesCdnUrl],
modules: [Autoplay, Pagination, Scrollbar],
})
const swiperContainerRef = useSwiper(swiperOptions, swiperStylesCdnUrl)
...otherStuff
</script>
<template>
<div>
<div>
<swiper-container ref="swiperContainerRef" :init="false">
<HomeCarouselSlideList :items="items" :carousel-height="carouselHeight" />
</swiper-container>
</div>
<div class="mt-1 space-y-4">
<div v-show="scrollbarEnabled" class="swiper-scrollbar"></div>
<div v-show="paginationEnabled" class="swiper-pagination"></div>
</div>
</div>
</template>
Hello all!
I have been working on a new branch that contains this work, but it seems that there is still some on going issues with swiper elements to make the full implementation.
Branch: https://github.com/cpreston321/nuxt-swiper/tree/feat/elements
@FranciscoKloganB Thanks again for initial research on how to best implement native web-components
! 🙏🏼
I really do appreciate the community helping me out it means the world.
Thanks, CP 🚀
I've actually updated the pseudo-code below to modify the useSwiper
composable. By using an Vue ref
and assigning it to <swiper-container ref="swiperContainerRef" :init="false">
my Swiper stopped breaking as I navigated across pages. It was also a problem that only happened in development, but no longer does. :)
The update still does not contemplate the "singleton register"
Good luck with the implementation! I hope my poc was useful in anyway.
Any news about elements branch? :)
@NeekoDev Yes! I got it working last week you can check it out here: https://github.com/cpreston321/nuxt-swiper/tree/feat/elements 😀
While testing there are some modules like creative-effects
not working with elements which seems to be upstream issue. I will submit an issue here soon. I also want a clean way to implement bundled
vs base
(meaning you have to import the styles and modules you want to enable on each instance of swiper). I also wanted to create some composables to help reference a swiper instance like how the current vue implementation.
In the meantime I am setting up a edge releases for elements so we can test in the mean time while keeping the current release as is. This will be good for reporting bugs etc.
Thanks, CP 🚀