SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/tailwind-image-galleries

6 Tailwind Image Galleries

3 Tailwind3 with JSPublished 2026-10-05Free · no sign-up

Six galleries built with Tailwind: thumbnails that open in a lightbox dialog, a product gallery with thumbnails, masonry columns, captions on hover, category filters and a pile of polaroid-style photos.

01. Tailwind Gallery with Lightbox

TailwindGalleryDialog

A thumbnail grid where each picture opens larger in a modal dialog with its caption. Thumbnails are buttons with descriptive names, and the dialog closes with Escape, the Close button or a click on the dimmed backdrop.

View code
<ul id="twig1" class="grid w-full max-w-xs grid-cols-3 gap-2">
  <li><button type="button" data-cap="Harbour at dusk" aria-label="Open photo: Harbour at dusk" style="background:linear-gradient(#fdba74,#f472b6 45%,#1e3a8a 46%,#0f172a)" class="block aspect-square w-full rounded-lg focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"></button></li>
  <li><button type="button" data-cap="Pine forest" aria-label="Open photo: Pine forest" style="background:linear-gradient(#bbf7d0,#15803d 60%,#14532d)" class="block aspect-square w-full rounded-lg focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"></button></li>
  <li><button type="button" data-cap="Desert dunes" aria-label="Open photo: Desert dunes" style="background:linear-gradient(#fef3c7,#f59e0b 55%,#b45309)" class="block aspect-square w-full rounded-lg focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"></button></li>
</ul>
<dialog id="twig1d" aria-labelledby="twig1c" class="w-[min(90vw,420px)] rounded-2xl bg-white p-3 backdrop:bg-black/70">
  <div id="twig1i" role="img" class="aspect-[4/3] rounded-xl"></div>
  <div class="mt-2 flex items-center justify-between"><p id="twig1c" class="text-sm font-semibold text-slate-900"></p><button type="button" data-close class="rounded-lg bg-slate-900 px-3 py-1.5 text-sm font-semibold text-white hover:bg-slate-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-900">Close</button></div>
</dialog>
var d = document.getElementById('twig1d'), im = document.getElementById('twig1i');
document.querySelectorAll('#twig1 button').forEach(function (b) { b.onclick = function () { im.style.background = b.style.background; im.setAttribute('aria-label', b.dataset.cap); document.getElementById('twig1c').textContent = b.dataset.cap; d.showModal(); }; });
d.querySelector('[data-close]').onclick = function () { d.close(); };
d.addEventListener('click', function (e) { if (e.target === d) d.close(); });

02. Tailwind Product Gallery with Thumbnails

TailwindGalleryProduct

A main product picture with a row of thumbnails underneath, as on a shop's product page. The selected thumbnail carries aria-current="true" and a ring, and the main picture's label changes with it.

View code
<div class="w-full max-w-[260px]">
  <div id="twig2m" role="img" aria-label="Ceramic mug, front" class="aspect-square rounded-2xl bg-[radial-gradient(circle_at_50%_55%,#0f766e_0_28%,transparent_29%),#ccfbf1]"></div>
  <div id="twig2t" class="mt-2 grid grid-cols-3 gap-2">
    <button type="button" aria-current="true" aria-label="Show front" data-label="Ceramic mug, front" data-bg="radial-gradient(circle at 50% 55%,#0f766e 0 28%,transparent 29%),#ccfbf1" class="aspect-square rounded-lg bg-teal-100 ring-offset-2 aria-[current=true]:ring-2 aria-[current=true]:ring-teal-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-teal-700"><span aria-hidden="true" class="mx-auto block size-6 rounded-full bg-teal-700"></span></button>
    <button type="button" aria-label="Show side" data-label="Ceramic mug, side with handle" data-bg="radial-gradient(ellipse at 45% 55%,#0f766e 0 24%,transparent 25%),radial-gradient(circle at 72% 55%,transparent 0 6%,#0f766e 7% 11%,transparent 12%),#ccfbf1" class="aspect-square rounded-lg bg-teal-100 ring-offset-2 aria-[current=true]:ring-2 aria-[current=true]:ring-teal-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-teal-700"><span aria-hidden="true" class="mx-auto block h-6 w-5 rounded-md bg-teal-700"></span></button>
    <button type="button" aria-label="Show top" data-label="Ceramic mug, top view" data-bg="radial-gradient(circle at 50% 50%,#134e4a 0 18%,#0f766e 19% 28%,transparent 29%),#ccfbf1" class="aspect-square rounded-lg bg-teal-100 ring-offset-2 aria-[current=true]:ring-2 aria-[current=true]:ring-teal-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-teal-700"><span aria-hidden="true" class="mx-auto block size-6 rounded-full border-4 border-teal-700 bg-teal-900"></span></button>
  </div>
</div>
var m = document.getElementById('twig2m'), bs = document.querySelectorAll('#twig2t button');
bs.forEach(function (b) { b.onclick = function () { bs.forEach(function (x) { x.removeAttribute('aria-current'); }); b.setAttribute('aria-current', 'true'); m.style.background = b.dataset.bg; m.setAttribute('aria-label', b.dataset.label); }; });

03. Tailwind Masonry Photo Gallery

TailwindGalleryMasonry

Pictures of different shapes flow into two columns with columns-2, each figure kept whole by break-inside-avoid. Aspect-ratio utilities set the shapes, and each caption sits under its picture.

View code
<div class="w-full max-w-xs columns-2 gap-2">
  <figure class="mb-2 break-inside-avoid"><div role="img" aria-label="Tall waterfall" class="aspect-[3/5] rounded-lg bg-[linear-gradient(#e0f2fe,#38bdf8_40%,#0c4a6e)]"></div><figcaption class="mt-1 text-xs text-slate-300">Waterfall</figcaption></figure>
  <figure class="mb-2 break-inside-avoid"><div role="img" aria-label="Wide meadow" class="aspect-[4/3] rounded-lg bg-[linear-gradient(#fef9c3,#a3e635_50%,#3f6212)]"></div><figcaption class="mt-1 text-xs text-slate-300">Meadow</figcaption></figure>
  <figure class="mb-2 break-inside-avoid"><div role="img" aria-label="Square city rooftop" class="aspect-square rounded-lg bg-[linear-gradient(#fda4af,#7c3aed_60%,#1e1b4b)]"></div><figcaption class="mt-1 text-xs text-slate-300">Rooftops</figcaption></figure>
  <figure class="mb-2 break-inside-avoid"><div role="img" aria-label="Tall lighthouse" class="aspect-[3/4] rounded-lg bg-[linear-gradient(#fde68a,#f97316_50%,#7c2d12)]"></div><figcaption class="mt-1 text-xs text-slate-300">Lighthouse</figcaption></figure>
</div>

04. Tailwind Gallery with Hover Captions

TailwindGalleryCaption

Captions fade in over the bottom of each picture on hover, with a gradient behind them for contrast. On touch screens the captions are always visible, and screen readers read them at all times.

View code
<ul class="grid w-full max-w-xs grid-cols-2 gap-2">
  <li><figure class="group relative overflow-hidden rounded-xl"><div role="img" aria-label="Boats in a harbour" class="aspect-square bg-[linear-gradient(#bae6fd,#0284c7_55%,#0c4a6e)]"></div><figcaption class="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/80 to-transparent p-2 pt-6 text-xs font-semibold text-white opacity-0 transition-opacity group-hover:opacity-100 [@media(hover:none)]:opacity-100">Harbour, Porto</figcaption></figure></li>
  <li><figure class="group relative overflow-hidden rounded-xl"><div role="img" aria-label="Orange grove" class="aspect-square bg-[radial-gradient(circle_at_40%_40%,#fb923c_0_14%,transparent_15%),linear-gradient(#bbf7d0,#166534)]"></div><figcaption class="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/80 to-transparent p-2 pt-6 text-xs font-semibold text-white opacity-0 transition-opacity group-hover:opacity-100 [@media(hover:none)]:opacity-100">Orange grove, Seville</figcaption></figure></li>
</ul>

05. Tailwind Filterable Gallery

TailwindGalleryFilter

Category buttons above the gallery show only matching pictures. The buttons are toggle buttons with aria-pressed, the hidden pictures use the hidden attribute, and a status line reports the count.

View code
<div class="w-full max-w-xs">
  <div id="twig5f" role="group" aria-label="Filter photos" class="flex gap-2 text-sm font-semibold">
    <button type="button" data-f="all" aria-pressed="true" class="rounded-full px-3 py-1 text-slate-700 ring-1 ring-slate-300 aria-pressed:bg-slate-900 aria-pressed:text-white aria-pressed:ring-slate-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">All</button>
    <button type="button" data-f="coast" aria-pressed="false" class="rounded-full px-3 py-1 text-slate-700 ring-1 ring-slate-300 aria-pressed:bg-slate-900 aria-pressed:text-white aria-pressed:ring-slate-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Coast</button>
    <button type="button" data-f="city" aria-pressed="false" class="rounded-full px-3 py-1 text-slate-700 ring-1 ring-slate-300 aria-pressed:bg-slate-900 aria-pressed:text-white aria-pressed:ring-slate-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">City</button>
  </div>
  <p id="twig5s" role="status" class="mt-2 text-xs text-slate-600">4 photos</p>
  <ul id="twig5" class="mt-1 grid grid-cols-2 gap-2">
    <li data-c="coast"><div role="img" aria-label="Cliffs over the sea" class="aspect-[4/3] rounded-lg bg-[linear-gradient(#bae6fd,#0369a1)]"></div></li>
    <li data-c="city"><div role="img" aria-label="Night skyline" class="aspect-[4/3] rounded-lg bg-[linear-gradient(#a78bfa,#1e1b4b)]"></div></li>
    <li data-c="coast"><div role="img" aria-label="Sandy cove" class="aspect-[4/3] rounded-lg bg-[linear-gradient(#fde68a,#0ea5e9)]"></div></li>
    <li data-c="city"><div role="img" aria-label="Tram street" class="aspect-[4/3] rounded-lg bg-[linear-gradient(#fdba74,#9a3412)]"></div></li>
  </ul>
</div>
var bs = document.querySelectorAll('#twig5f button'), items = document.querySelectorAll('#twig5 li');
bs.forEach(function (b) { b.onclick = function () { var f = b.dataset.f, n = 0; bs.forEach(function (x) { x.setAttribute('aria-pressed', x === b); }); items.forEach(function (li) { var on = f === 'all' || li.dataset.c === f; li.hidden = !on; if (on) n++; }); document.getElementById('twig5s').textContent = n + ' photos'; }; });

06. Tailwind Polaroid Photo Pile

TailwindGalleryPolaroid

Instant-photo frames scattered at slight angles, each straightening and lifting on hover. A white frame with a deeper bottom edge and a handwritten-style caption gives the snapshot look.

View code
<ul class="flex w-full max-w-xs justify-center -space-x-6 py-4">
  <li><figure class="w-28 -rotate-6 bg-white p-2 pb-6 shadow-lg transition hover:relative hover:z-10 hover:rotate-0 hover:scale-110 motion-reduce:transition-none"><div role="img" aria-label="Beach at noon" class="aspect-square bg-[linear-gradient(#bae6fd_55%,#fde68a_55%)]"></div><figcaption class="mt-1 text-center font-serif text-xs italic text-slate-700">Beach day</figcaption></figure></li>
  <li><figure class="w-28 rotate-3 bg-white p-2 pb-6 shadow-lg transition hover:relative hover:z-10 hover:rotate-0 hover:scale-110 motion-reduce:transition-none"><div role="img" aria-label="Birthday cake with candles" class="aspect-square bg-[linear-gradient(#fbcfe8_50%,#f472b6_50%)]"></div><figcaption class="mt-1 text-center font-serif text-xs italic text-slate-700">Turning 30</figcaption></figure></li>
  <li><figure class="w-28 -rotate-2 bg-white p-2 pb-6 shadow-lg transition hover:relative hover:z-10 hover:rotate-0 hover:scale-110 motion-reduce:transition-none"><div role="img" aria-label="Snowy mountain" class="aspect-square bg-[linear-gradient(160deg,#f8fafc_40%,#94a3b8_41%,#334155)]"></div><figcaption class="mt-1 text-center font-serif text-xs italic text-slate-700">Alps</figcaption></figure></li>
</ul>

About these Tailwind Image Galleries

Thumbnails are buttons

A thumbnail that opens something larger is a button with a name such as Open photo: Harbour at dusk.

Lightbox on dialog

showModal() traps focus and closes on Escape; backdrop:bg-black/70 dims the page.

Masonry with columns

columns-2 and break-inside-avoid make a masonry gallery; reading order runs down each column.

Captions for everyone

Hover captions should still be readable by screen readers and always visible on touch screens through [@media(hover:none)]:opacity-100.

Frequently asked questions

Can I use real images?

Yes. Replace the gradient placeholders with img elements and alt text, keeping the classes.

Should images be lazy loaded?

Yes, add loading="lazy" to images below the fold.

Is there a CSS version?

Yes, see the CSS image galleries collection.