22 Tailwind CSS Image Gallery

20 Pure Tailwind2 Tailwind + JSPublished

22 CSS Tailwind image galleries for portfolio and photography sites, e-commerce product grids, editorial magazine spreads, and marketing lightboxes — spanning masonry and justified layouts, honeycomb and metro mosaics, scroll-snap filmstrips, :target lightboxes, 3D tilt and cube viewers, Ken Burns slideshows, and infinite marquees. Scoped under .tgl-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.

Related22 Tailwind CSS Image Carousel22 CSS Image Galleries22 CSS Image Carousels

Premium upgradePartner: Untitled UI

Affiliate link

Building a whole Tailwind app, not just this component?

You just browsed 22 Tailwind image gallery. Untitled UI Pro unlocks 5,000+ components and sections and 250+ page examples for React, styled with Tailwind CSS v4. One licence is a one-time $349 with lifetime updates; teams start at $999.

Get Untitled UI Pro

Untitled UI React. We may earn a commission, at no extra cost to you.

Published

Pure Tailwind
An interlocking honeycomb where square portraits are clipped into hexagons and packed into offset rows with no gaps — the dense geometric grid team pages and portfolios reach for. The port's win is that the hex geometry, the hover zoom and the label reveal all sit on the cell that owns them, so a cell is copy-pasteable in one piece.

04. Tailwind :has() Hover Spotlight Image Grid (opens in a new tab)

Published

Pure Tailwind
Hover any card and every other card in the grid dims and desaturates, spotlighting the one you are on. The behaviour that used to need a JavaScript mouseenter loop is one relational selector — and in Tailwind it is one arbitrary variant, declared on the grid that owns the relationship.

Published

Tailwind + JS
A canvas where photographs bloom behind the cursor, drift and fade. CSS owns every frame of the motion; twelve lines of JavaScript decide only where and when to spawn. In Tailwind the spawned node's entire look is one class string the script assigns, which is the cleanest possible split between behaviour and style.
Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

FAQ

Frequently asked questions

How does the masonry gallery work without JavaScript, and why do my cards read in the wrong order?
Demo 07 builds masonry with the CSS columns property — you set a column count and gap, drop the images in, and the browser flows them top-to-bottom, filling each column automatically with no measuring script. The trade-off you must know: columns lays items out column by column, not row by row, so the DOM order reads down column one, then down column two. That is fine for a loose photo wall but wrong for anything sequential like a dated feed. The classic bug is a card splitting across the column break; guard every item with break-inside: avoid so a single photo never tears in half. If you need strict left-to-right reading order, reach for the Metro grid in Demo 08 instead, which uses grid auto-flow and lays tiles in source order.
How does the :has() hover spotlight dim every card except the one I am on?
Demo 04 dims and desaturates every card except the hovered one using the :has() parent selector. The grid says when I contain a hovered child, fade all my children, then a more specific rule re-brightens the one under the pointer — roughly .grid:has(.card:hover) .card { opacity: .4 } paired with .card:hover { opacity: 1 }. It needs no JavaScript because :has() lets a parent react to a descendant's state. Two things bite people: first, drive the dim from the container, not from siblings via ~, or hovering the last card cannot affect earlier ones. Second, in engines without :has() every card simply stays at full brightness — a graceful fallback, not a break, but test your floor. Add :focus-within alongside :hover so keyboard users get the same spotlight.
How does the pure CSS lightbox open a full image with no JavaScript?
Demo 10 is a full lightbox with zero JavaScript. Each thumbnail is a link whose href points at the id of a hidden full-size figure; clicking it sets the URL fragment, and the :target selector matches the figure whose id equals that fragment, switching it from display: none to a centred, scaled overlay. A second link with a # href clears the fragment to close. Because state lives in the URL, the browser Back button closes the lightbox for free and each open image is deep-linkable. The accessibility caveat: give the close control a real aria-label and make the backdrop itself a closing link so pointer and keyboard both escape. If you need to trap focus inside the modal or lock body scroll, that is where you outgrow pure CSS and want a scripted <dialog> element instead.
Why does my infinite image marquee show a visible seam or jump when it loops?
Demo 19 scrolls a row of images forever with no visible jump. The trick is duplication: you render the image sequence twice back-to-back inside one flex track, then animate the track with transform: translateX from 0 to -50%. When the animation loops, the second copy sits exactly where the first began, so the reset is invisible. The most common bug — a seam or stutter — always comes from the two halves not being identical, or from a gap on the track that the -50% does not account for. Keep the copies exact and put the gap inside each half. Animate transform, never margin or left, so motion stays on the compositor and does not repaint each frame. Pause on :hover for readability, and wrap it in @media (prefers-reduced-motion: reduce) to stop it for users who ask.
How does the justified gallery keep every photo uncropped while filling the row edge to edge?
Demo 02 is the Google-Images look: full-width rows where every photo keeps its native shape and nothing is cropped. Each row is a flex container; each photo carries its real aspect-ratio and grows with flex-grow proportional to that ratio, so wide panoramas take more of the row and tall shots take less, yet every image in a row shares one height and the row fills edge to edge. It works without a layout script because aspect-ratio lets the browser compute each item's width from a single shared height. Watch the last row: with too few images it can stretch one photo grotesquely wide, so cap growth or left-align the final row. Use this when preserving composition matters — portraits and landscapes side by side — and avoid it when you want a rigid uniform grid, where Demo 13's contained-zoom mosaic is the better fit.
Does the 3D tilt card effect need JavaScript, or can I do it in pure CSS?
Demo 16 tilts each card in 3D toward the cursor with a moving glare, and this one is the exception in the set — it needs a few lines of JavaScript, because CSS cannot read pointer coordinates on its own. A pointermove handler writes the cursor position into two CSS custom properties on the card, and the stylesheet does the rest: rotateX and rotateY off those variables, plus a radial-gradient glare positioned by the same values. Keep the handler cheap — update only the custom properties, let CSS transform, and never write layout properties from the event. Add a perspective on the parent or the rotation looks flat. If you want real 3D with no script at all, Demo 17's cube uses hidden radio inputs to drive rotation and Demo 18's depth stack fans out on :focus — both give you 3D without a pointer listener.
Are these hover-driven galleries accessible to keyboard and screen reader users?
Several demos reveal or expand on hover — the accordion strips in Demo 12, the expanding panels in Demo 03, the diagonal slice reveal in Demo 15. Hover alone excludes keyboard and touch users, so each one pairs :hover with :focus or :focus-within and uses a focusable element as the trigger. That means the interactive item is a real link or button, not a bare <div>, so it enters the tab order and shows a visible focus ring. Give icon-only controls an aria-label, mark decorative frames with aria-hidden, and always supply meaningful alt text on the photos — a gallery of empty alt attributes is invisible to screen readers. Finally, honour @media (prefers-reduced-motion: reduce) on the auto-playing ones like the Ken Burns slideshow in Demo 20 and the marquee, disabling the transform so motion-sensitive users are not forced through it.
When should I not use these gallery patterns, and how do I pick the right one?
Pick by content, not by novelty. The hexagon honeycomb in Demo 01 and the diagonal slice in Demo 15 both use clip-path, which crops the image to a shape — great for uniform portraits, bad for photos whose subject sits near an edge, because the clip slices it off. The scattered collage in Demo 22 and the Polaroid stack in Demo 21 rotate and overlap items, which reads as intentional for a casual mood board but hurts scannability in a product catalogue where alignment signals order. The Ken Burns slideshow in Demo 20 shows one image at a time, so it is wrong when users need to compare or scan many photos quickly — a grid serves that better. And columns masonry in Demo 07 flows top-to-bottom, so avoid it whenever reading order must run left-to-right. Match the pattern to how people will actually consume the images.

Related collections

30 CSS Badges preview

30 CSS Badges

30 hand-coded CSS badges for status indicators, notifications, membership tiers, live-data displays, and SEO / DevOps / financial dashboards — upload progress, typing indicator, transit line status, Core Web Vitals, ECG heartbeat, CI/CD build pipeline, countdown ring, live price ticker, keycap shortcut, wax seal, conference lanyard, and holographic collectibles. Copy-paste HTML and CSS, WCAG 2.2 accessible, MIT licensed.

20 CSS Banners & Alerts preview

20 CSS Banners & Alerts

20 hand-coded CSS banner and alert bars for e-commerce storefronts, SaaS dashboards, marketing sites, and compliance-bound products. Covers GDPR cookie consent with a real preferences panel, promo bars with countdown timers, free-shipping threshold progress, app-install smart banners, maintenance and incident status bars, newsletter signup bars, age verification gates, limited-stock urgency banners, live event announcements, browser upgrade notices, geo and currency switchers, sticky top announcement bars, bottom cookie bars, inline form validation alerts, icon-aligned alert banners, left-border accent alerts, diagonal stripe promos, full-width hero banners, animated gradient border alerts, and a text-wrapping laboratory that shows five strategies for the unbreakable string that breaks more banners than anything else. Every bar is scoped under a .ba-NN prefix for no-collision pasting, guards prefers-reduced-motion, carries the correct aria-live and role semantics, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.

25 CSS Blockquotes preview

25 CSS Blockquotes

25 CSS blockquotes for article pull quotes, testimonial cards, docs callout admonitions, statement banners, and social-post embeds. Covers giant decorative quotation marks, minimalist hairline and classic left borders, animated gradient and glowing neon borders, glassmorphism and aurora backgrounds, brutalist cards, speech bubbles, thick accent rails, highlighted mark text, newspaper multi-column layouts, an expandable read-more disclosure, a scroll-snap testimonial slider, and one-click copy.

Search CodeFronts

Loading…