React.children.map dont work with repeat for each element

Hello,

I have registered a custom Swiper component that maps children and creates a swiper slide for each child. Here’s the code:

export const Carousel: React.FC<CarouselProps> = ({ children }) => {
  return (
    <Swiper
      slidesPerView={"auto"}
      spaceBetween={24}
      autoplay={{
        delay: 2500,
        disableOnInteraction: false,
      }}
      modules={[Autoplay]}
    >
      {React.Children.map(children, (child, index) => {
        return <SwiperSlide key={`${index}`}>{child}</SwiperSlide>;
      })}
    </Swiper>
  );
};

While everything works properly when manually adding child elements:

When using a dynamic data list to repeat each element, React.Children.map receives the list as a single element instead of multiple elements:

How can i fix this issue ?

Hi @yuval222,

To resolve this issue, you can click on Edit Carousel → Advanced options → Use children for slides and bind dynamic slide content

Loom: Loom | Free Screen & Video Recording Software | Loom

Hi @manish-sharma

Thank you for your detailed response.

My use case is different because I have implemented a custom component called ‘Carousel’, as I require different functionality than what is provided by the built-in builder carousel.

As previously mentioned, passing a list of children manually works correctly. However, when binding it with a dynamic data list and repeating each item, it is passed as a single child containing a list of items. This causes React.Children.map to not work as expected.

Hi @yuval222,

If you could share the code for the custom carousel component, that would help us reproduce this from our end and possibly offer you a quick solution. Thank you!

Hi @manish-sharma

export const Carousel: React.FC<CarouselProps> = ({ children }) => {
  return (
    <Swiper
      slidesPerView={"auto"}
      spaceBetween={24}
      autoplay={{
        delay: 2500,
        disableOnInteraction: false,
      }}
      modules={[Autoplay]}
    >
      {React.Children.map(children, (child, index) => {
        return <SwiperSlide key={`${index}`}>{child}</SwiperSlide>;
      })}
    </Swiper>
  );
};

Hi @yuval222,

Could you also share the code for registering the swiper component with builder?

const CarouselWithChildren = withChildren(Carousel);

Builder.registerComponent(CarouselWithChildren, {
  name: "Carousel",
  inputs: [
    {
      name: "autoplay",
      friendlyName: "Autoplay",
      type: "boolean",
      defaultValue: true,
      helperText: "Enable autoplay",
    },
    {
      name: "slidesPerView",
      friendlyName: "Slides per view",
      type: "string",
      defaultValue: "auto",
      helperText: "Number of slides per view",
      enum: ["auto", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
    },
    {
      name: "effect",
      friendlyName: "Effect",
      type: "string",
      defaultValue: "fade",
      enum: ["fade", "creative"],
      showIf: (options: any) => options.get("slidesPerView") === "1",
    },
    {
      name: "spaceBetween",
      friendlyName: "Space between",
      type: "string",
      defaultValue: "24",
      helperText: "Space between slides",
      enum: ["24", "32"],
    },
  ],
});

@manish-sharma Have you managed to reproduce the issue?

Hi, @yuval222!

Yes, We have reproduced this issue and are working on a possible solution.

Hey guys,
Do you find any concrete solution of this ?
@manish-sharma @yuval222

@hafiz not that i know yet.
@manish-sharma any updates?

Do you find any concrete solution of this ?
@manish-sharma

Hello @sohaibVanguard-x @hafiz @yuval222,

Here is an example that works for us

import { builder, Builder, BuilderBlocks, withChildren } from '@builder.io/react'

// Import Swiper React components
import { Swiper, SwiperSlide, Autoplay } from 'swiper/react';

const Carousel: React.FC<CarouselProps> = ( props ) => {
  const {
    children,
    content,
    builderBlock,
  } = props;
  return (
    <Swiper
      slidesPerView={"auto"}
      spaceBetween={24}
      autoplay={{
        delay: 2500,
        disableOnInteraction: false,
      }}
    >
      {React.Children.map(children, (child, index) => {
        return (<SwiperSlide key={`${index}`}>
          {child}
          <BuilderBlocks
          parentElementId={builderBlock.id}
          style={{
            width: "200px",
            height: "200px",
          }}
          dataPath="component.options.content"
          blocks={content}
        />
          </SwiperSlide>);
      })}
    </Swiper>
  );
};



const CarouselWithChildren = withChildren(Carousel);

Builder.registerComponent(CarouselWithChildren, {
  name: "Carousel",
  inputs: [
    {
      name: "autoplay",
      friendlyName: "Autoplay",
      type: "boolean",
      defaultValue: true,
      helperText: "Enable autoplay",
    },
    {
      name: "slidesPerView",
      friendlyName: "Slides per view",
      type: "string",
      defaultValue: "auto",
      helperText: "Number of slides per view",
      enum: ["auto", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
    },
    {
      name: "effect",
      friendlyName: "Effect",
      type: "string",
      defaultValue: "fade",
      enum: ["fade", "creative"],
      showIf: (options: any) => options.get("slidesPerView") === "1",
    },
    {
      name: "spaceBetween",
      friendlyName: "Space between",
      type: "string",
      defaultValue: "24",
      helperText: "Space between slides",
      enum: ["24", "32"],
    },
    {
      name: "content",
      type: "uiBlocks",
      defaultValue: [],
    },
  ],
});

Hi @manish-sharma i have implemented your suggestion but still facing same issue.
this is my code

import {
builder,
Builder,
BuilderBlocks,
withChildren,
} from “@builder.io/react”;
import React from “react”;

// Import Swiper React components
import { Swiper, SwiperSlide } from “swiper/react”;

const CarouselComponent: React.FC = (props) => {
const { children, content, builderBlock } = props;
return (
<Swiper
slidesPerView={“auto”}
spaceBetween={24}
autoplay={{
delay: 2500,
disableOnInteraction: false,
}}
>
{React.Children.map(children, (child, index) => {
return (
<SwiperSlide key={${index}}>
{child}
<BuilderBlocks
parentElementId={builderBlock.id}
style={{
width: “200px”,
height: “200px”,
}}
dataPath=“component.options.content”
blocks={content}
/>

);
})}

);
};

export const ReactCarousel = withChildren(CarouselComponent);

Builder.registerComponent(ReactCarousel, {
name: “Carousel”,
inputs: [
{
name: “autoplay”,
friendlyName: “Autoplay”,
type: “boolean”,
defaultValue: true,
helperText: “Enable autoplay”,
},
{
name: “slidesPerView”,
friendlyName: “Slides per view”,
type: “string”,
defaultValue: “auto”,
helperText: “Number of slides per view”,
enum: [“auto”, “1”, “2”, “3”, “4”, “5”, “6”, “7”, “8”, “9”, “10”],
},
{
name: “effect”,
friendlyName: “Effect”,
type: “string”,
defaultValue: “fade”,
enum: [“fade”, “creative”],
showIf: (options: any) => options.get(“slidesPerView”) === “1”,
},
{
name: “spaceBetween”,
friendlyName: “Space between”,
type: “string”,
defaultValue: “24”,
helperText: “Space between slides”,
enum: [“24”, “32”],
},
{
name: “content”,
type: “uiBlocks”,
defaultValue: ,
},
],
});

this is how i can apply
image