Astro.js map data into components

I have a list of objects I would like to map into components in Astro. Here's my Carousel.astro component:
<astro-carousel>
<div class="swiper">
<div class="swiper-wrapper">
{
items.map((item) => {
<div class="swiper-slide">
<CarouselItem title={item.title} description={item.description} />
</div>;
})
}
</div>
</div>
<div class="navigation-buttons">
<button class="previous-button"></button>
<button class="next-button"></button>
</div>
</astro-carousel>
<astro-carousel>
<div class="swiper">
<div class="swiper-wrapper">
{
items.map((item) => {
<div class="swiper-slide">
<CarouselItem title={item.title} description={item.description} />
</div>;
})
}
</div>
</div>
<div class="navigation-buttons">
<button class="previous-button"></button>
<button class="next-button"></button>
</div>
</astro-carousel>
And here is the call inside of index.astro:
---
const carouselItems = [
{
title: "Video",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce a nulla eget massa sagittis ultricies",
},
{
title: "Video",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce a nulla eget massa sagittis ultricies",
},
{
title: "Video",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce a nulla eget massa sagittis ultricies",
},
];
---

<Carousel items={carouselItems} />
---
const carouselItems = [
{
title: "Video",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce a nulla eget massa sagittis ultricies",
},
{
title: "Video",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce a nulla eget massa sagittis ultricies",
},
{
title: "Video",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce a nulla eget massa sagittis ultricies",
},
];
---

<Carousel items={carouselItems} />
However, nothing is being show on my website, and nothing is rendered in the DOM. In the Astro docs, they have a simple example here (https://docs.astro.build/en/core-concepts/astro-components/):
<ul>
{myFavoritePokemon.map((data) => <li>{data.name}</li>)}
</ul>
<ul>
{myFavoritePokemon.map((data) => <li>{data.name}</li>)}
</ul>
I thought this would be something really simple, but nothing is working. I've tried to remove my CarouselItem component and just render the item properties by themselves but even that doesn't render anything in the DOM. I am also sure that my data is available. Am I missing something obvious?
18 Replies
vince
vince•11mo ago
Okay I've narrowed it down a bit. It seems when I map over the items outside of my swiper container, it works fine. When I put them inside the swiper container, it doesn't even render the components in the DOM. Here is my full (minus CSS) Carousel.astro component:
---
import CarouselItem from "../components/CarouselItem.astro";

interface Props {
items: { title: string; description: string }[];
}

const { items } = Astro.props;
---

// Works

{
items.map((item) => (
<CarouselItem title={item.title} description={item.description} />
))
}


// Doesn't work

<div class="carousel">
<div class="swiper">
<div class="swiper-wrapper">
{
items.map((item) => {
<div class="swiper-slide">
<CarouselItem title={item.title} description={item.description} />
</div>;
})
}
</div>
</div>
<div class="navigation-buttons">
<button class="previous-button"></button>
<button class="next-button"></button>
</div>
</div>

<script>
import Swiper from "swiper";
import { Navigation } from "swiper/modules";
import "swiper/css";

const swiper = new Swiper(".swiper", {
modules: [Navigation],
slidesPerView: 1.25,
spaceBetween: "16",

navigation: {
nextEl: ".next-button",
prevEl: ".previous-button",
},
});
</script>
---
import CarouselItem from "../components/CarouselItem.astro";

interface Props {
items: { title: string; description: string }[];
}

const { items } = Astro.props;
---

// Works

{
items.map((item) => (
<CarouselItem title={item.title} description={item.description} />
))
}


// Doesn't work

<div class="carousel">
<div class="swiper">
<div class="swiper-wrapper">
{
items.map((item) => {
<div class="swiper-slide">
<CarouselItem title={item.title} description={item.description} />
</div>;
})
}
</div>
</div>
<div class="navigation-buttons">
<button class="previous-button"></button>
<button class="next-button"></button>
</div>
</div>

<script>
import Swiper from "swiper";
import { Navigation } from "swiper/modules";
import "swiper/css";

const swiper = new Swiper(".swiper", {
modules: [Navigation],
slidesPerView: 1.25,
spaceBetween: "16",

navigation: {
nextEl: ".next-button",
prevEl: ".previous-button",
},
});
</script>
I'd think it was maybe the way everything's loaded into the DOM, but Astro renders the components during build time, so the resulting HTML from the map should already be there by the time the swiper library runs client-side
croganm
croganm•11mo ago
I hate recommending this as I've had this bug before and I wasn't very happy with doing it this way. Could you try making a slot within Carousel.astro where the map goes, and then inside the Carousel element in your index.astro, could you call that map there as a slot item? I have no idea what causes it and I should have created a github issue but, based off memory, that fixed it for me If that doesn't work It's something with swiper
vince
vince•11mo ago
Like this right? Carousel.astro:
<div class="carousel">
<div class="swiper">
<div class="swiper-wrapper">
<slot />
</div>
</div>
<div class="navigation-buttons">
<button class="previous-button"></button>
<button class="next-button"></button>
</div>
</div>
<div class="carousel">
<div class="swiper">
<div class="swiper-wrapper">
<slot />
</div>
</div>
<div class="navigation-buttons">
<button class="previous-button"></button>
<button class="next-button"></button>
</div>
</div>
index.astro:
<Carousel>
{
carouselItems.map((item) => (
<CarouselItem title={item.title} description={item.description} />
))
}
</Carousel>
<Carousel>
{
carouselItems.map((item) => (
<CarouselItem title={item.title} description={item.description} />
))
}
</Carousel>
It renders on the DOM now, and the slides are in the right spots, but I'm not able to switch slides
croganm
croganm•11mo ago
Exactly like that. Glad it renders now at least.... But I almost have a feeling swipe is removing the dom elements.... Now I feel bad asking this but what happens if you go back to the old way and just comment our the swiper code 😅
vince
vince•11mo ago
Lol no worries, thanks for your help so far! Giving me new ideas. I tried that let me try it again and see Well now I'm really confused 😂 I just switched back the old way, and regardless if I comment out the swiper.js code or not, it renders the elements... but even with the swiper code not commented out, the functionality is still broken I restarted localhost just in case, still the same thing
croganm
croganm•11mo ago
If the functionality is broken, it's just an issue with the swiper config
vince
vince•11mo ago
Hm... it works though without the custom components 😂 Already posted that, I forgot haha
croganm
croganm•11mo ago
Wait.... Oh nvm, give me a second Thinking 😂
vince
vince•11mo ago
Definitely haha, I'll continue to mess around with it
croganm
croganm•11mo ago
Do you get any console logs or anything?
vince
vince•11mo ago
Nope lol Ah Wth It works now
croganm
croganm•11mo ago
Oh astro lol. Did you change anything?
vince
vince•11mo ago
I forgot to add back the wrapping .swiper-slide div when I changed it back and now it works. I swear to god I had this before though 😂
{
items.map((item) => (
<div class="swiper-slide">
<CarouselItem title={item.title} description={item.description} />
</div>
))
}
{
items.map((item) => (
<div class="swiper-slide">
<CarouselItem title={item.title} description={item.description} />
</div>
))
}
It's what I originally had in my example Maybe resetting the dev server helped?
croganm
croganm•11mo ago
Haha well regardless, glad it's working now!!
vince
vince•11mo ago
I am too, thank you a ton for helping me croganm 🙂 I was already sitting here for like 2 hours banging my head against the wall and it would have been another 2 hours without you rubber ducky-ing for me 😂
croganm
croganm•11mo ago
Yea my pleasure! Rubber ducking is real man, I firmly believe it 😂
Tenkes
Tenkes•11mo ago
@vince I believe issue was that you used qurly brackets in arrow function inside your items.map:
{
items.map((item) => {
<div class="swiper-slide">
<CarouselItem title={item.title} description={item.description} />
</div>
})
}
{
items.map((item) => {
<div class="swiper-slide">
<CarouselItem title={item.title} description={item.description} />
</div>
})
}
instead of regular ones:
{
items.map((item) => (
<div class="swiper-slide">
<CarouselItem title={item.title} description={item.description} />
</div>
))
}
{
items.map((item) => (
<div class="swiper-slide">
<CarouselItem title={item.title} description={item.description} />
</div>
))
}
vince
vince•11mo ago
Omg yup that was it! Thank you so much! I make that mistake in React too 😂