swiper: Children does not render properly (after wrapper component)

Hello, I have already posted on stackoverflow about rendering children in swiperjs using React.

https://stackoverflow.com/questions/66993033/swiper-js-for-react-does-not-render-children-properly I use:

"gatsby": "^3.0.1",
"react": "^17.0.1",
"swiper": "^6.5.0",

What You Did

I want to render children like this: <Swiper>{children}<Swiper/> But children are rendered after swiper wrapper.

Expected Behavior

I want to pass all children and render them inside Swiper wrapper because I fetch data from external source (headless cms)

Actual Behavior

Swiper Slides are rendered after Swiper component what makes cards invisible in page content.

The code you can see in stack overflow and this commit of my project https://github.com/tobiaszciesielski/tciesielski.pl/pull/1/commits/5500865d7eef1a99facb03e3dedd987ee1ce6033

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 17
  • Comments: 15

Most upvoted comments

Had the same issue, and fixed it with an even simpler solution. Let me know if you see any concerns.

All I needed to do was change the displayName of my ‘custom slide’ component to match the “SwiperSlide” component so the parent “Swiper” thinks the direct child is “SwiperSlide”.

export const BannerSliderSlide = () => {
  return (
    <SwiperSlide>
          // Add custom code here...
    </SwiperSlide>
  );
};

BannerSliderSlide.displayName = 'SwiperSlide'; <-- ** ADDED THIS **

This makes me really sad.

@jomarquez21 I encoutered same issue when i tried to use subcomponents and here is the workaroud i found :

Carousel.tsx

import React, { ReactNode } from 'react'
import { Swiper, SwiperSlide } from 'swiper/react'
import SwiperCore, { Keyboard, Mousewheel, Navigation } from 'swiper'

type CarouselComposition = {
  Item: typeof Item
}

export type CarouselProps = {
  children: ReactNode
}

SwiperCore.use([Navigation, Mousewheel, Keyboard])

export const Carousel: React.VFC<CarouselProps> & CarouselComposition = ({ children }) => {
  return (
    <Swiper>
      {/* workaround because swiper needs SwiperSlide as direct children
      @see https://github.com/nolimits4web/swiper/issues/4413
      @see https://github.com/nolimits4web/swiper/issues/4084
      */}
      {React.Children.map(children, (child: ReactNode) => (
        <SwiperSlide>{child}</SwiperSlide>
      ))}
    </Swiper>
  )
}

type ItemProps = {
  children: ReactNode
}
const Item = ({ children }: ItemProps) => {
  return <>{children}</>
}
Carousel.Item = Item

Component.tsx

...
return  (
  <Carousel>
    {Array.from(Array(10).fill(0)).map((_, i) => {
      return (
        <Carousel.Item key={i}>
            Slide {i}
        </Carousel.Item>
      )
    })}
  </Carousel>
)
...

Thanks for the solution @msoyka.

Sharing a ‘deeper slides’ situation here. Just the first level needs the edit.

// Root
<Swiper>
  <SwiperSlide className={styles.planningTypesSlide}> // not nested, no problem at all
     <PlanningTypesSlide />  
  </SwiperSlide>
  <NestedSlides/> // displayName needs editing
</Swiper>
// NestedSlides.jsx
<>
  <SwiperSlide className={styles.planningTypesSlide}> // not nested, no problem at all
     <AnotherCustomSlide />  
  </SwiperSlide>
  <DeeperNestedSlides /> // surprisingly, no need to edit displayName here
</>

@nolimits4web is this considered an error? If this is a bug, can you add the corresponding tag?

In case it helps anyone, I just recently faced this issue as well but in this context:

I was pulling from different components that each were wrapped in a SwiperSlide (inside the component). Reading up on the above shows that Swiper wants the SwiperSlides to be a direct child so to get it working I removed the SwiperSlide inside each component and wrapped them with SwiperSlide outside of the component, inside the Carousel component.

From

Carousel.tsx

case 'newsArticles_default_Entry':
  return (
      <NewsArticleSlide content={content} />
  );
case 'podcasts_default_Entry':
  return (
      <PodcastSlide content={content} />
  );

Slide.tsx

return (
    <SwiperSlide key={id}>
        <article>
            ...markup
        </article>
    </SwiperSlide>
  )

To

Carousel.tsx

case 'newsArticles_default_Entry':
  return (
    <SwiperSlide key={content.id}>
      <NewsArticleSlide content={content} />
    </SwiperSlide>
  );
case 'podcasts_default_Entry':
  return (
    <SwiperSlide key={content.id}>
      <PodcastSlide content={content} />
    </SwiperSlide>
  );

Slide.tsx

return (
    <article>
        ...markup
    </article>
  )