Pure TailwindMIT licensed

Tailwind Masonry Image Gallery with CSS Columns (No JavaScript)

The Pinterest classic and the single most-searched gallery pattern in Tier-1 markets: staggered columns where images of different heights pack tightly with no gaps and no layout library. In Tailwind the entire layout is three utilities — columns-4, gap-3.5, break-inside-avoid.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="tgl-07 w-full min-h-svh flex items-start justify-center bg-tgl07-bg font-tgl07-sans px-5 py-10" aria-label="Masonry photo gallery">
  <div class="w-[min(920px,100%)] columns-4 gap-3.5 max-[820px]:columns-3 max-[560px]:columns-2">
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1584917865442-de89df76afd3?q=80&w=500&h=700&auto=format&fit=crop" alt="Snow-capped mountain ridge at dawn" loading="lazy" decoding="async" width="500" height="700" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1524504388940-b1c1722653e1?q=80&w=500&h=400&auto=format&fit=crop" alt="Misty pine forest canopy" loading="lazy" decoding="async" width="500" height="400" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1536440136628-849c177e76a1?q=80&w=500&h=560&auto=format&fit=crop" alt="Still alpine lake reflecting the sky" loading="lazy" decoding="async" width="500" height="560" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?q=80&w=500&h=620&auto=format&fit=crop" alt="Rolling desert sand dunes" loading="lazy" decoding="async" width="500" height="620" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1526170375885-4d8ecf77b99f?q=80&w=500&h=380&auto=format&fit=crop" alt="Turquoise ocean waves from above" loading="lazy" decoding="async" width="500" height="380" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?q=80&w=500&h=680&auto=format&fit=crop" alt="Tall waterfall in a green gorge" loading="lazy" decoding="async" width="500" height="680" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1509631179647-0177331693ae?q=80&w=500&h=460&auto=format&fit=crop" alt="City skyline at blue hour" loading="lazy" decoding="async" width="500" height="460" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1470770841072-f978cf4d019e?q=80&w=500&h=540&auto=format&fit=crop" alt="Autumn trees in gold and red" loading="lazy" decoding="async" width="500" height="540" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1449157291145-7efd050a4d0e?q=80&w=500&h=420&auto=format&fit=crop" alt="Layered red canyon walls" loading="lazy" decoding="async" width="500" height="420" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1599566150163-29194dcaad36?q=80&w=500&h=600&auto=format&fit=crop" alt="Green aurora over a snowy valley" loading="lazy" decoding="async" width="500" height="600" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tgl07-bg: #f4f5f7;
  --color-tgl07-bg: oklch(0.97 0.003 265);
  --color-tgl07-well: #e7eaef;
  --color-tgl07-well: oklch(0.92 0.006 265);
  --color-tgl07-acc: #3d6ed6;
  --color-tgl07-acc: oklch(0.58 0.16 260);
  --font-tgl07-sans: 'Space Grotesk', system-ui, sans-serif;
}

.tgl-07 {
  width: 100%;
  min-height: 100svh;
}

.tgl-07 ::selection {
  background: var(--color-tgl07-acc);
  color: #fff;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Compiles in the browser — perfect for a CodePen or a quick test, not for production.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-tgl07-bg: #f4f5f7;
  --color-tgl07-bg: oklch(0.97 0.003 265);
  --color-tgl07-well: #e7eaef;
  --color-tgl07-well: oklch(0.92 0.006 265);
  --color-tgl07-acc: #3d6ed6;
  --color-tgl07-acc: oklch(0.58 0.16 260);
  --font-tgl07-sans: 'Space Grotesk', system-ui, sans-serif;
}

.tgl-07 {
  width: 100%;
  min-height: 100svh;
}

.tgl-07 ::selection {
  background: var(--color-tgl07-acc);
  color: #fff;
}
3Fonts used by this demooptional — skip if you have your own type stack
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • Three CSS declarations become three utilities and the media queries disappear into max-[820px]:columns-3. This is the most economical port in the collection: the Tailwind version is genuinely shorter than the CSS it replaces.
  • The zoom pair uses group-focus-within: rather than group-focus-visible: because the focusable element here would be a link wrapped around the image, not the figure itself.
  • UI change from the CSS original: the card shadow now transitions on hover as well as the image scale, so a hovered tile lifts off the light stage instead of only zooming.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Masonry Image Gallery with CSS Columns (No JavaScript)
Source: https://codefronts.com/snippets/tailwind-css-image-gallery/tailwind-masonry-image-gallery-css-columns/

The Pinterest classic and the single most-searched gallery pattern in Tier-1 markets: staggered columns where images of different heights pack tightly with no gaps and no layout library. In Tailwind the entire layout is three utilities — columns-4, gap-3.5, break-inside-avoid.
## HTML
```html
<section class="tgl-07 w-full min-h-svh flex items-start justify-center bg-tgl07-bg font-tgl07-sans px-5 py-10" aria-label="Masonry photo gallery">
  <div class="w-[min(920px,100%)] columns-4 gap-3.5 max-[820px]:columns-3 max-[560px]:columns-2">
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1584917865442-de89df76afd3?q=80&w=500&h=700&auto=format&fit=crop" alt="Snow-capped mountain ridge at dawn" loading="lazy" decoding="async" width="500" height="700" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1524504388940-b1c1722653e1?q=80&w=500&h=400&auto=format&fit=crop" alt="Misty pine forest canopy" loading="lazy" decoding="async" width="500" height="400" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1536440136628-849c177e76a1?q=80&w=500&h=560&auto=format&fit=crop" alt="Still alpine lake reflecting the sky" loading="lazy" decoding="async" width="500" height="560" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?q=80&w=500&h=620&auto=format&fit=crop" alt="Rolling desert sand dunes" loading="lazy" decoding="async" width="500" height="620" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1526170375885-4d8ecf77b99f?q=80&w=500&h=380&auto=format&fit=crop" alt="Turquoise ocean waves from above" loading="lazy" decoding="async" width="500" height="380" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?q=80&w=500&h=680&auto=format&fit=crop" alt="Tall waterfall in a green gorge" loading="lazy" decoding="async" width="500" height="680" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1509631179647-0177331693ae?q=80&w=500&h=460&auto=format&fit=crop" alt="City skyline at blue hour" loading="lazy" decoding="async" width="500" height="460" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1470770841072-f978cf4d019e?q=80&w=500&h=540&auto=format&fit=crop" alt="Autumn trees in gold and red" loading="lazy" decoding="async" width="500" height="540" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1449157291145-7efd050a4d0e?q=80&w=500&h=420&auto=format&fit=crop" alt="Layered red canyon walls" loading="lazy" decoding="async" width="500" height="420" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
    <figure class="group break-inside-avoid m-0 mb-3.5 rounded-xl overflow-hidden bg-tgl07-well shadow-[0_8px_22px_-16px_oklch(0.3_0.04_265/0.6)] transition-shadow duration-300 hover:shadow-[0_16px_34px_-18px_oklch(0.3_0.04_265/0.55)]"><img src="https://images.unsplash.com/photo-1599566150163-29194dcaad36?q=80&w=500&h=600&auto=format&fit=crop" alt="Green aurora over a snowy valley" loading="lazy" decoding="async" width="500" height="600" class="block w-full h-auto transition-transform duration-500 ease-[cubic-bezier(0.2,0.7,0.2,1)] group-hover:scale-[1.06] group-focus-within:scale-[1.06] motion-reduce:transition-none"></figure>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tgl07-bg: #f4f5f7;
  --color-tgl07-bg: oklch(0.97 0.003 265);
  --color-tgl07-well: #e7eaef;
  --color-tgl07-well: oklch(0.92 0.006 265);
  --color-tgl07-acc: #3d6ed6;
  --color-tgl07-acc: oklch(0.58 0.16 260);
  --font-tgl07-sans: 'Space Grotesk', system-ui, sans-serif;
}

.tgl-07 {
  width: 100%;
  min-height: 100svh;
}

.tgl-07 ::selection {
  background: var(--color-tgl07-acc);
  color: #fff;
}
```

How this works

Multi-column is still the right baseline. Native grid masonry remains experimental, and columns-* is supported everywhere. Tailwind maps it directly, so the whole layout reads in one class list:

<div class="columns-4 gap-3.5 max-[820px]:columns-3 max-[560px]:columns-2">

Reading order is the trade. Columns fill top-to-bottom then left-to-right, so visual order runs down each column. For photographs that is fine and screen-reader order still follows the DOM; for ordered content, use a grid instead.

The hover is contained. The figure clips, the image scales. Nothing about the column geometry moves, so hovering the tenth photo cannot reflow the first nine.

Make it yours

  • Column count: columns-4, or columns-[18rem] for width-driven auto-responsive columns.
  • Density: gap-3.5 plus the figure's mb-3.5 — both need changing together, since column-gap and vertical rhythm are separate axes here.
  • Progressive-enhance to row-order masonry behind an @supports query when the native property ships.

Gotchas — read before shipping

  • break-inside-avoid is not optional. Without it an image tears across the column break, and it will only show up on some column counts.
  • gap-3.5 sets column-gap here, not row spacing — the vertical rhythm comes from each figure's bottom margin.
  • Give every <img> intrinsic width/height so the column heights resolve before the photos arrive; this is the demo where lazy loading most easily causes layout shift.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

CSS multi-column is universal; the floor is Tailwind v4's generated sheet. Native grid-template-rows: masonry is still experimental, which is why this baseline uses columns.

Techniques used in this demo

Search CodeFronts

Loading…