Stackbits is going through a refresh! Some features may not be available. Follow @stackbitss on twitter for updates.
Components > Image Pile

Image Pile

ImagePile shuffles and layers images dynamically, creating a stylish, ever-changing visual effect. Built with React, Next.js, Framer Motion, and Tailwind CSS, it’s perfect for portfolios, galleries, and landing pages. Add motion and personality to your UI effortlessly! πŸš€πŸŽ¨

Preview

stacked-card-0
stacked-card-1
stacked-card-2
stacked-card-3
stacked-card-4

Follow below steps πŸ‘‡πŸ»

Install dependencies

npm i framer-motion

Component

Create a file image-pile.tsx in your components folder and paste this code

'use client'; import React, { useEffect, useState } from 'react'; import Image from 'next/image'; import { motion } from 'framer-motion'; const ImagePile = ({ images, speed = 2 }: { images: string[]; speed?: number }) => { const [topIndex, setTopIndex] = useState(0); useEffect(() => { const id = setInterval(() => { setTopIndex((prevIndex) => (prevIndex + 1) % images.length); }, speed * 1000); return () => { clearInterval(id); }; }, [images.length]); return ( <div className="relative h-[200px] sm:h-[260px] md:h-[390px] lg:h-[450px] xl:h-[500px] w-[310px] sm:w-[500px] md:w-[725px] lg:w-[900px] xl:w-[1200px] overflow-visible"> {images.map((image, i) => { const key = `stacked-card-${i}`; const isTop = topIndex === i; const secondTopIndex = (topIndex + 2) % images.length; const zIndex = isTop ? 100 : secondTopIndex ? 99 : images.length - i; const y: number = Math.random() * 20; const x: number = Math.random() * 20; const rotation = i * (Math.random() * 1 + 2) - 2; return ( <motion.div key={key} className="absolute w-full h-full" style={{ zIndex, transformOrigin: 'center center' }} animate={{ rotateZ: isTop ? 0 : rotation, translateX: Math.random() < 0.5 ? x : -x, opacity: isTop ? [0, 1] : 0.8, translateY: isTop ? [30, Math.random() < 0.5 ? y : -y] : Math.random() < 0.5 ? y : -y, transition: { duration: 0.5 } }} initial={isTop ? { rotateZ: 0 } : { rotateZ: rotation }} > <div className="relative h-full w-full overflow-hidden rounded-3xl"> <Image src={image} alt={`stacked-card-${i}`} height={1080} width={1920} className="h-full w-full object-cover" priority={isTop} /> </div> </motion.div> ); })} </div> ); }; export default ImagePile;

Usage

<ImagePile images={[ 'https://images.unsplash.com/photo-1731770241468-8337b047749f?q=80&w=3870&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', 'https://images.unsplash.com/photo-1728993559783-f657d4177c6b?q=80&w=3870&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', 'https://images.unsplash.com/photo-1638392436949-3e584046314a?q=80&w=3870&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', 'https://images.unsplash.com/photo-1726880066148-fdc1ceba7343?q=80&w=3876&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D' ]} />