All components
Images Slider
carouselsAceternity UI component.
responsive · 700px
Install
Same command in any shadcn project — React (Vite/CRA), Next.js, Remix, Astro, and more:
$
npx shadcn@latest add https://your-domain/r/images-slider.jsonUsage
"use client";
import { ImagesSlider } from "@/registry/aceternity-ui/images-slider";
import { motion } from "motion/react";
export default function Demo() {
const images = [
"https://picsum.photos/seed/slider1/1200/700",
"https://picsum.photos/seed/slider2/1200/700",
"https://picsum.photos/seed/slider3/1200/700",
"https://picsum.photos/seed/slider4/1200/700",
];
return (
<div className="w-full max-w-3xl mx-auto" style={{ height: "400px" }}>
<ImagesSlider images={images} className="h-full">
<motion.div
initial={{ opacity: 0, y: -80 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="z-50 flex flex-col justify-center items-center"
>
<motion.p className="font-bold text-xl md:text-6xl text-center bg-clip-text text-transparent bg-gradient-to-b from-neutral-50 to-neutral-400 py-4">
The hero section slideshow <br /> nobody asked for
</motion.p>
<button className="px-4 py-2 backdrop-blur-sm border bg-emerald-300/10 border-emerald-500/20 text-white mx-auto text-center rounded-full relative mt-4">
<span>Explore now</span>
<div className="absolute inset-x-0 h-px -bottom-px bg-gradient-to-r w-3/4 mx-auto from-transparent via-emerald-500 to-transparent" />
</button>
</motion.div>
</ImagesSlider>
</div>
);
}Component source
"use client";
import { cn } from "@/lib/utils";
import { motion, AnimatePresence } from "motion/react";
import React, { useEffect, useState } from "react";
export const ImagesSlider = ({
images,
children,
overlay = true,
overlayClassName,
className,
autoplay = true,
direction = "up",
}: {
images: string[];
children: React.ReactNode;
overlay?: React.ReactNode;
overlayClassName?: string;
className?: string;
autoplay?: boolean;
direction?: "up" | "down";
}) => {
const [currentIndex, setCurrentIndex] = useState(0);
const [loading, setLoading] = useState(false);
const [loadedImages, setLoadedImages] = useState<string[]>([]);
const handleNext = () => {
setCurrentIndex((prevIndex) =>
prevIndex + 1 === images.length ? 0 : prevIndex + 1
);
};
const handlePrevious = () => {
setCurrentIndex((prevIndex) =>
prevIndex - 1 < 0 ? images.length - 1 : prevIndex - 1
);
};
useEffect(() => {
loadImages();
}, []);
const loadImages = () => {
setLoading(true);
const loadPromises = images.map((image) => {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = image;
img.onload = () => resolve(image);
img.onerror = reject;
});
});
Promise.all(loadPromises)
.then((loadedImages) => {
setLoadedImages(loadedImages as string[]);
setLoading(false);
})
.catch((error) => console.error("Failed to load images", error));
};
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "ArrowRight") {
handleNext();
} else if (event.key === "ArrowLeft") {
handlePrevious();
}
};
window.addEventListener("keydown", handleKeyDown);
// autoplay
let interval: any;
if (autoplay) {
interval = setInterval(() => {
handleNext();
}, 5000);
}
return () => {
window.removeEventListener("keydown", handleKeyDown);
clearInterval(interval);
};
}, []);
const slideVariants = {
initial: {
scale: 0,
opacity: 0,
rotateX: 45,
},
visible: {
scale: 1,
rotateX: 0,
opacity: 1,
transition: {
duration: 0.5,
ease: [0.645, 0.045, 0.355, 1.0] as const,
},
},
upExit: {
opacity: 1,
y: "-150%",
transition: {
duration: 1,
},
},
downExit: {
opacity: 1,
y: "150%",
transition: {
duration: 1,
},
},
};
const areImagesLoaded = loadedImages.length > 0;
return (
<div
className={cn(
"overflow-hidden h-full w-full relative flex items-center justify-center",
className
)}
style={{
perspective: "1000px",
}}
>
{areImagesLoaded && children}
{areImagesLoaded && overlay && (
<div
className={cn("absolute inset-0 bg-black/60 z-40", overlayClassName)}
/>
)}
{areImagesLoaded && (
<AnimatePresence>
<motion.img
key={currentIndex}
src={loadedImages[currentIndex]}
initial="initial"
animate="visible"
exit={direction === "up" ? "upExit" : "downExit"}
variants={slideVariants}
className="image h-full w-full absolute inset-0 object-cover object-center"
/>
</AnimatePresence>
)}
</div>
);
};Dependencies
motion
Source: Aceternity UI