Stackbits
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

1
npm i framer-motion

Component

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

1
'use client';
2
3
import React, { useEffect, useState } from 'react';
4
import Image from 'next/image';
5
import { motion } from 'framer-motion';
6
7
const ImagePile = ({ images, speed = 2 }: { images: string[]; speed?: number }) => {
8
const [topIndex, setTopIndex] = useState(0);
9
10
useEffect(() => {
11
const id = setInterval(() => {
12
setTopIndex((prevIndex) => (prevIndex + 1) % images.length);
13
}, speed * 1000);
14
15
return () => {
16
clearInterval(id);
17
};
18
}, [images.length]);
19
20
return (
21
<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">
22
{images.map((image, i) => {
23
const key = `stacked-card-${i}`;
24
const isTop = topIndex === i;
25
const secondTopIndex = (topIndex + 2) % images.length;
26
const zIndex = isTop ? 100 : secondTopIndex ? 99 : images.length - i;
27
const y: number = Math.random() * 20;
28
const x: number = Math.random() * 20;
29
const rotation = i * (Math.random() * 1 + 2) - 2;
30
31
return (
32
<motion.div
33
key={key}
34
className="absolute w-full h-full"
35
style={{
36
zIndex,
37
transformOrigin: 'center center'
38
}}
39
animate={{
40
rotateZ: isTop ? 0 : rotation,
41
translateX: Math.random() < 0.5 ? x : -x,
42
opacity: isTop ? [0, 1] : 0.8,
43
translateY: isTop ? [30, Math.random() < 0.5 ? y : -y] : Math.random() < 0.5 ? y : -y,
44
transition: {
45
duration: 0.5
46
}
47
}}
48
initial={isTop ? { rotateZ: 0 } : { rotateZ: rotation }}
49
>
50
<div className="relative h-full w-full overflow-hidden rounded-3xl">
51
<Image
52
src={image}
53
alt={`stacked-card-${i}`}
54
height={1080}
55
width={1920}
56
className="h-full w-full object-cover"
57
priority={isTop}
58
/>
59
</div>
60
</motion.div>
61
);
62
})}
63
</div>
64
);
65
};
66
67
export default ImagePile;

Usage

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

⭐️ Got a question or feedback?
Feel free to reach out!