File Stack
FileStack is a modern, animated component designed to display files, images, or media in an interactive, stacked layout. With smooth hover effects, subtle floating animations, and a 3D perspective, FileStack brings a dynamic feel to your UI. Perfect for portfolios, media galleries, or product showcases, it enhances engagement by revealing file details on hover. Built with Next.js, Tailwind CSS, and Framer Motion, FileStack ensures seamless performance while keeping your design sleek and intuitive. Whether you're displaying documents, images, or featured content, FileStack makes it visually stunning and user-friendly. 🚀
Preview
Follow below steps 👇🏻
Install dependencies
1npm i framer-motion tailwindcss-animate
Component
Create a file file-stack.tsx in your components folder and paste this code
1'use client';23import Image from 'next/image';4import React, { useState } from 'react';5import { motion, AnimatePresence } from 'framer-motion';67type FileStackItem = {8title: string;9image: string;10description: string;11link?: string; // Optional link for clickable items12};1314interface FileStackProps {15items: FileStackItem[];16spacing?: number; // Customizable spacing between items17}1819const FileStack = ({ items, spacing = 10 }: FileStackProps) => {20const [isHovered, setIsHovered] = useState<number | null>(null);21const [isLoading, setIsLoading] = useState<{ [key: string]: boolean }>({});2223// Subtle floating animation24const floatingAnimation = {25y: [0, -5, 0],26transition: {27duration: 4,28repeat: Infinity,29ease: 'easeInOut'30}31};3233// Calculate consistent spacing value for each card34const getCardSpacing = (index: number) => {35if (index === 0) return 0;36return `-${spacing}rem`;37};3839return (40<div className="h-full w-full relative group">41{/* Gradient Overlay with Text */}42<div className="h-full w-full bg-gradient-to-b from-[#000000da] pointer-events-none to-transparent rounded-lg absolute z-10 flex flex-col">43<AnimatePresence>44{isHovered !== null && (45<motion.div46key={isHovered + 'text'}47initial={{ opacity: 0, y: 100 }}48animate={{ opacity: 1, y: 0, transition: { delay: 0.2 } }}49exit={{ opacity: 0, y: -100 }}50transition={{ duration: 0.2 }}51className="flex flex-col items-center justify-center mt-2 p-4"52>53<motion.h254className="text-center font-bold text-2xl mb-2"55animate={{ scale: [1, 1.02, 1] }}56transition={{ duration: 1, repeat: Infinity }}57>58{items[isHovered].title}59</motion.h2>60<p className="text-center text-neutral-300 max-w-[500px] line-clamp-2">61{items[isHovered].description}62</p>63</motion.div>64)}65</AnimatePresence>66</div>6768{/* Main FileStack Content */}69<div70style={{ perspective: '1000px' }}71className="flex flex-col h-full w-full items-center overflow-y-auto relative pt-[30%]"72>73{items.map((item, i) => (74<motion.div75key={i}76onMouseEnter={() => setIsHovered(i)}77onMouseLeave={() => setIsHovered(null)}78initial={{79rotateX: -50,80marginTop: getCardSpacing(i)81}}82animate={!isHovered ? floatingAnimation : undefined}83whileHover={{84rotateX: 0,85marginBottom: '7rem',86scale: 1.02,87boxShadow:88'0 0 30px 5px rgba(255, 255, 255, 0.2), inset 0 0 15px rgba(255, 255, 255, 0.1)',89transition: { duration: 0.3 }90}}91className={`92flex relative rounded-md flex-col items-center93max-w-[500px] justify-center bg-neutral-800 p-294${item.link ? 'cursor-pointer' : ''}95transition-shadow duration-30096hover:shadow-xl hover:shadow-neutral-900/2097`}98onClick={() => item.link && window.open(item.link, '_blank')}99>100{/* FileStack Edge Detail */}101<div className="h-4 w-20 bg-neutral-800 rounded-ss-md rounded-se-md absolute -top-2" />102103{/* Loading State */}104{isLoading[item.image] && (105<div className="absolute inset-0 flex items-center justify-center bg-neutral-800/50">106<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-white" />107</div>108)}109110{/* Image */}111<div className="relative w-full overflow-hidden rounded-sm">112<Image113src={item.image}114alt={item.title}115height={400}116width={400}117className="object-cover h-full max-w-[350px] transition-all duration-300"118onLoadingComplete={() => setIsLoading((prev) => ({ ...prev, [item.image]: false }))}119onLoadStart={() => setIsLoading((prev) => ({ ...prev, [item.image]: true }))}120priority={i < 2}121/>122</div>123124{/* Hover Indicator */}125<motion.div126className="absolute bottom-0 left-1/2 -translate-x-1/2 w-1/3 h-1 bg-white/50 rounded-full"127initial={{ scaleX: 0 }}128whileHover={{ scaleX: 1 }}129/>130</motion.div>131))}132</div>133</div>134);135};136137export default FileStack;
Usage
1<FileStack2items={[3{4title: 'Urban Skyline',5image:6'https://images.unsplash.com/photo-1718563552473-2d97b224e801?w=900&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxmZWF0dXJlZC1waG90b3MtZmVlZHw1fHx8ZW58MHx8fHx8',7description:8'A breathtaking view of a modern cityscape with towering skyscrapers illuminated at dusk.'9},10{11title: 'Mountain Retreat',12image:13'https://images.unsplash.com/photo-1735317461815-1a0ba64e9a56?w=900&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxmZWF0dXJlZC1waG90b3MtZmVlZHwyMXx8fGVufDB8fHx8fA%3D%3D',14description:15'A serene cabin nestled in the heart of towering mountains, perfect for a peaceful getaway.'16},17{18title: 'Forest Wander',19image:20'https://images.unsplash.com/photo-1502082553048-f009c37129b9?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',21description:22'A misty trail winding through a dense, enchanting forest filled with lush greenery.'23},24{25title: 'Serene Lake',26image:27'https://images.unsplash.com/photo-1504384308090-c894fdcc538d?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',28description:29'A tranquil lake reflecting the golden hues of the sunset, surrounded by peaceful nature.'30},31{32title: 'Golden Hour',33image:34'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',35description:36'A mesmerizing sunset casting a warm glow over the ocean, creating a dreamlike atmosphere.'37},38{39title: 'Coastal Vibes',40image:41'https://images.unsplash.com/photo-1493558103817-58b2924bce98?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',42description:43'Crystal-clear waves crashing against a sandy shore, offering a perfect beach escape.'44},45{46title: 'Night Lights',47image:48'https://images.unsplash.com/photo-1502933691298-84fc14542831?w=900&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Mnx8d2F0ZXIlMjBzcG9ydHxlbnwwfHwwfHx8MA%3D%3D',49description:50'A dazzling city skyline at night, with vibrant lights illuminating the urban landscape.'51},52{53title: 'Rustic Charm',54image:55'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80',56description:57'A cozy wooden cabin with a warm, inviting atmosphere set in a countryside setting.'58}59]}60></FileStack>
⭐️ Got a question or feedback?
Feel free to reach out!