I have a Shadcn UI carousel that should display a bunch of images; the carousel controls are there and they seem to fit into the screen, but the images are not being displayed.
Note: If I replace the property fill
with the width and height I see the image.
This is my component:
"use client";
import { getAllImages } from "@/lib/appwrite";
import { useQuery } from "@tanstack/react-query";
import React, { useEffect, useState } from "react";
import {
Carousel,
CarouselApi,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel";
import Image from "next/image";
import { Loader2, AlertCircle } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
export default function FullScreenCarousel() {
const [api, setApi] = useState<CarouselApi>();
const [current, setCurrent] = useState(0);
const [count, setCount] = useState(0);
const {
data: images,
error,
isLoading,
} = useQuery({
queryKey: ["images"],
queryFn: getAllImages,
});
useEffect(() => {
if (!api) return;
setCount(api.scrollSnapList().length);
setCurrent(api.selectedScrollSnap() + 1);
api.on("select", () => {
setCurrent(api.selectedScrollSnap() + 1);
});
}, [api]);
if (isLoading) {
return (
<div className="flex justify-center items-center h-screen">
<Loader2 className="h-12 w-12 animate-spin text-primary" />
</div>
);
}
if (error || !images || images.length === 0) {
return (
<Alert variant="destructive" className="m-4">
<AlertCircle className="h-4 w-4" />
<AlertTitle>Error</AlertTitle>
<AlertDescription>
Hubo un problema al cargar las imágenes. Por favor, intenta de nuevo
más tarde.
</AlertDescription>
</Alert>
);
}
return (
<div className="h-screen w-full relative">
<Carousel setApi={setApi} className="h-full">
<CarouselContent className="h-full">
{images.map((image, index) => (
<CarouselItem key={image.$id} className="h-full">
<div className="relative h-full w-full">
<Image
src={image.url}
alt={image.alt}
priority={index === 0}
loading={index === 0 ? "eager" : "lazy"}
className="object-cover"
sizes="100vw"
fill
style={{
objectFit: 'cover'
}}
/>
<div className="absolute inset-0 bg-black bg-opacity-40 flex flex-col justify-end p-6 text-white">
<h2 className="text-2xl md:text-4xl font-bold mb-2">
{image.titulo}
</h2>
<p className="text-sm md:text-lg">{image.descripcion}</p>
</div>
</div>
</CarouselItem>
))}
</CarouselContent>
<CarouselPrevious className="absolute left-4 top-1/2 -translate-y-1/2" />
<CarouselNext className="absolute right-4 top-1/2 -translate-y-1/2" />
</Carousel>
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 bg-black bg-opacity-50 text-white px-4 py-2 rounded-full">
{current} / {count}
</div>
</div>
);
}
According to the NextJS documentation, I should be able to use fill
to fill the carousel. Any suggestions?
3
Answers
to be able to use the fill with object-fit: cover properties your parent div should have relative with height and width classes then it will be fixed.
When using
fill
the image will take its parentheight
andwidth
and its bubbling up to thisdiv class="overflow-hidden"
By default, div has 0 height until it takes the height of elements inside it but in our case the image want to inherit the height of its parent this caused the bug.
Without something likes
position: absolute
thatdiv
won’t take the height of its parent.One way to fix this is to change
display
of the carousel togrid
because grid items always fillout their parents height evenlyWorking example: https://stackblitz.com/edit/stackblitz-starters-vhrqbu?file=app%2Fpage.tsx
The issue with the fill property in the Next.js Image component is that it requires the parent element to have both position: relative and a defined height. Without these, the image won’t render correctly.
To resolve this:
This should allow the images to display correctly using the fill property.