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

Masonry Grid

Masonry Grid is the perfect solution for dynamic, Pinterest-style layouts that adapt beautifully to any screen size. Built with React, Next.js, and Tailwind CSS, this grid intelligently arranges elements into an optimized, gap-free layout, making it ideal for image galleries, portfolios, and product listings. Say goodbye to rigid rows and columns—Masonry Grid ensures your content flows seamlessly, no matter the shape or size. Fully responsive, lightweight, and easy to customize, this component helps you create visually stunning layouts without the hassle. Get started with StackBits and elevate your UI with effortless grid magic! 🚀

Preview

Urban Skyline
Mountain Retreat
Forest Wander
Serene Lake
Golden Hour
Coastal Vibes
Night Lights
Rustic Charm
Blooming Meadows
Mystic Mountains
Abstract Art
Desert Mirage
City Buzz
Urban Skyline
Mountain Retreat
Forest Wander
City Buzz
Quiet Alley
Vibrant Street
Quiet Alley
Vibrant Street
Calm Waters
Snowy Peaks
Sunset Bliss
Cultural Heritage
Modern Minimalism
Calm Waters
Snowy Peaks
Sunset Bliss
Cultural Heritage
Modern Minimalism
Serene Lake
Golden Hour
Coastal Vibes
Night Lights
Rustic Charm
Blooming Meadows
Mystic Mountains
Abstract Art
Desert Mirage

Follow below steps 👇🏻

Install dependencies

npm i framer-motion tailwindcss-animate

Component

Create a file masonry-grid.tsx in your components folder and paste this code

'use client'; import React, { useState } from 'react'; import { motion } from 'framer-motion'; import Image from 'next/image'; interface MasonryGridProps { items: { image: string; title: string; description: string }[]; columns?: number | undefined; } const MasonryGrid: React.FC<MasonryGridProps> = ({ items, columns = undefined }) => { const [imagesLoaded, setImagesLoaded] = useState<{ [key: string]: boolean }>({}); if (!items || items.length === 0) { return <div className="text-center p-4">No items to display</div>; } return ( <div style={{ columns: columns }} className={`${ !columns && 'columns-1 sm:columns-2 md:columns-3 lg:columns-4' } gap-2 overflow-y-auto p-3 w-full`} > {items.map((item, index) => { // Calculate row number based on screen size and index const getColumnCount = () => { if (typeof window === 'undefined') return 1; const width = window.innerWidth; if (width >= 1024) return 4; // lg if (width >= 768) return 3; // md if (width >= 640) return 2; // sm return 1; }; const columnCount = getColumnCount(); const rowIndex = Math.floor(index / columnCount); return ( <motion.div key={index} className="break-inside-avoid mb-4 relative group rounded-xl overflow-hidden p-1 border-[1px] border-transparent hover:border-[1px] hover:border-neutral-800" initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0, transition: { duration: 0.5, delay: rowIndex * 0.1, ease: 'easeOut' } }} whileHover={{ scale: 1.05, rotateZ: 1 }} > <div className="relative"> <div className="relative w-full flex gap-1 flex-col items-start justify-start"> {!imagesLoaded[item.image] && ( <div className="absolute inset-0 w-full h-[300px] bg-neutral-500/50 animate-pulse rounded-lg" /> )} <Image src={item.image} alt={item.title} width={400} height={300} className={`${ !imagesLoaded[item.image] ? 'opacity-0' : 'opacity-100' } w-full h-auto transition-transform duration-300 rounded-lg`} sizes="(max-width: 640px) 100vw, (max-width: 768px) 50vw, (max-width: 1024px) 33vw, 25vw" onLoad={() => { setImagesLoaded((prev) => ({ ...prev, [item.image]: true })); }} onError={() => { console.error(`Error loading image: ${item.image}`); setImagesLoaded((prev) => ({ ...prev, [item.image]: true })); }} /> {imagesLoaded[item.image] && ( <div className="w-full"> <h3 className="text-sm font-medium">{item.title}</h3> <p className="mt-0 text-xs text-neutral-500 line-clamp-2 overflow-hidden"> {item.description} </p> </div> )} </div> </div> </motion.div> ); })} </div> ); }; export default MasonryGrid;

Usage

<MasonryGrid items={[ { title: 'Urban Skyline', image: 'https://images.unsplash.com/photo-1718563552473-2d97b224e801?w=900&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxmZWF0dXJlZC1waG90b3MtZmVlZHw1fHx8ZW58MHx8fHx8', description: 'A breathtaking view of a modern cityscape with towering skyscrapers illuminated at dusk.' }, { title: 'Mountain Retreat', image: 'https://images.unsplash.com/photo-1735317461815-1a0ba64e9a56?w=900&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxmZWF0dXJlZC1waG90b3MtZmVlZHwyMXx8fGVufDB8fHx8fA%3D%3D', description: 'A serene cabin nestled in the heart of towering mountains, perfect for a peaceful getaway.' }, { title: 'Forest Wander', image: 'https://images.unsplash.com/photo-1502082553048-f009c37129b9?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80', description: 'A misty trail winding through a dense, enchanting forest filled with lush greenery.' }, { title: 'Serene Lake', image: 'https://images.unsplash.com/photo-1504384308090-c894fdcc538d?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80', description: 'A tranquil lake reflecting the golden hues of the sunset, surrounded by peaceful nature.' }, { title: 'Golden Hour', image: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80', description: 'A mesmerizing sunset casting a warm glow over the ocean, creating a dreamlike atmosphere.' }, { title: 'Coastal Vibes', image: 'https://images.unsplash.com/photo-1493558103817-58b2924bce98?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80', description: 'Crystal-clear waves crashing against a sandy shore, offering a perfect beach escape.' }, { title: 'Night Lights', image: 'https://images.unsplash.com/photo-1502933691298-84fc14542831?w=900&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Mnx8d2F0ZXIlMjBzcG9ydHxlbnwwfHwwfHx8MA%3D%3D', description: 'A dazzling city skyline at night, with vibrant lights illuminating the urban landscape.' }, { title: 'Rustic Charm', image: 'https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?ixlib=rb-4.0.3&auto=format&fit=crop&w=400&q=80', description: 'A cozy wooden cabin with a warm, inviting atmosphere set in a countryside setting.' } ]} ></MasonryGrid>