Components / Gallery
Gallery Grid
Free Gallery React component — GalleryGridCard. MIT licensed, copy-paste ready for Next.js and Tailwind CSS.
Album preview with title, subtitle, and a three-cell photo grid — last cell shows a +N overflow count. Portfolio and gallery index pages.
Preview
Summer Collection
24 photos · Jun 2026



Setup
How to use
Free for personal and commercial use. No UI attribution required. Include the MIT copyright notice when copying component source into your project. Read the MIT license.
- 1
Run in your terminal:
$npm install clsx tailwind-merge lucide-react - 2
Copy
lib/cn.tsbelow. Skip if you already havecn(). - 3
Copy the code below and create
components/gallery/gallery-grid-card.tsxin your project. - 4
Import and render:
Exampleimport { GalleryGridCard } from "@/components/gallery/gallery-grid-card";
lib/cn.ts
import { type ClassValue, clsx } from "clsx";import { twMerge } from "tailwind-merge";export function cn(...inputs: ClassValue[]) {return twMerge(clsx(inputs));}
components/gallery/gallery-grid-card.tsx
import {forwardRef,type ComponentPropsWithoutRef,type ReactNode,} from "react";import Image from "next/image";import { cn } from "@/lib/cn";import { Sun } from "lucide-react";export type GalleryGridCardProps = Readonly<{title?: string;subtitle?: string;count?: string | number;images?: string[];overlayText?: string;icon?: ReactNode;} & ComponentPropsWithoutRef<"div">>;// Production-ready Gallery Grid component — styled with Tailwind CSS.export const GalleryGridCard = forwardRef<HTMLDivElement, GalleryGridCardProps>(({className,title = "Summer Collection",subtitle = "Jun 2026",count = "24 photos",images = ["/wallpaper-15.png", "/wallpaper-3.png", "/wallpaper-11.png"],overlayText = "+21",icon,...props},ref,) => {return (<divref={ref}data-slot="gallery-grid-card"className={cn("w-72 overflow-hidden rounded-2xl border border-neutral-100 bg-white font-sans shadow-lg",className,)}{...props}><div className="flex items-center justify-between p-3 pb-2"><div><h3 className="text-sm font-semibold text-neutral-900">{title}</h3><p className="text-[10px] text-neutral-400">{count} · {subtitle}</p></div>{icon ?? <Sun className="text-neutral-500" size={16} />}</div>{/* Grid */}<div className="grid grid-cols-3 gap-1 px-3 pb-3">{/* Main large image */}<div className="relative col-span-2 row-span-2 aspect-square overflow-hidden rounded-xl"><Imagesrc={images[0]}alt={title}fillsizes="288px"className="object-cover transition-transform duration-500 hover:scale-105"/></div>{/* Small image 1 */}<div className="relative aspect-square overflow-hidden rounded-xl"><Imagesrc={images[1]}alt={title}fillsizes="96px"className="object-cover"/></div>{/* Small image 2 with overlay */}<div className="relative aspect-square overflow-hidden rounded-xl"><Imagesrc={images[2]}alt={title}fillsizes="96px"className="object-cover"/><div className="absolute inset-0 flex items-center justify-center bg-black/50"><span className="text-xs font-semibold text-white">{overlayText}</span></div></div></div></div>);},);GalleryGridCard.displayName = "GalleryGridCard";