Getting Started
Accordion
Barricade Tape
Buttons
Browser Window
Contact Section
File Stack
Glass Grid
NewGooey Words
Glowing Dots Background
Image Pile
Jelly Loader
Mask Cursor Effect
NewMagnet Tabs
Masonry Grid
Pixelated Carousel
NewPixelated Text
NewPrismatic Haze Background
Projects Section
Proximity Background
Proximity Lift Grid
Skeumorphic Music Card
Spotlight Grid
Texts
Trading Card
Wavy Background
NewImage 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
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'
]}
/>