11 / 22
All 22 in 22 Tailwind CSS Image Gallery
- 01Tailwind Hexagon Honeycomb Image Gallery with clip-path
- 02Tailwind Justified Image Gallery with Aspect-Ratio Flex Rows
- 03Tailwind Expanding Panel Image Gallery with Flex-Grow Transitions
- 04Tailwind :has() Hover Spotlight Image Grid
- 05Tailwind Radial Orbit Image Gallery with Counter-Rotating Thumbnails
- 06Tailwind Interactive Pointer Trail Image Gallery
- 07Tailwind Masonry Image Gallery with CSS Columns (No JavaScript)
- 08Tailwind Metro Tile Grid Gallery with Dense Auto-Flow
- 09Tailwind Editorial Magazine Grid Gallery with Blend-Mode Headline
- 10Tailwind Pure CSS Lightbox Gallery with :target (No JavaScript)
- 11Tailwind Filmstrip Carousel Gallery with CSS Scroll-Snap
- 12Tailwind Accordion Image Gallery with Flex-Grow on Hover & Focus
- 13Tailwind Mosaic Grid Gallery with Contained Zoom on Hover
- 14Tailwind Glassmorphism Image Cards with backdrop-blur
- 15Tailwind Diagonal Slice Reveal Gallery with clip-path Halves
- 16Tailwind 3D Tilt Parallax Image Cards with Pointer-Driven Variables
- 17Tailwind 3D Cube Image Viewer with Radio-Driven Rotation
- 18Tailwind 3D Perspective Depth Stack Gallery That Fans on Focus
- 19Tailwind Infinite Scrolling Image Marquee with Seamless Loop
- 20Tailwind Ken Burns Slideshow Gallery with Staggered Cross-Fade
- 21Tailwind Polaroid Photo Stack Gallery with Rotate-on-Hover
- 22Tailwind Scattered Photo Collage with :target Spotlight
Tailwind Filmstrip Carousel Gallery with CSS Scroll-Snap
A low-profile strip of thumbnails that scrolls and snaps like a camera filmstrip, sprocket holes included. Tailwind ships the whole snap family as utilities, so the carousel — normally a library — is five classes on a container and one on each frame.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tgl-11 w-full min-h-svh grid place-items-center bg-tgl11-bg font-tgl11-sans py-10" aria-label="Filmstrip carousel gallery">
<div tabindex="0" role="region" aria-label="Scrollable filmstrip, use arrow keys" class="flex gap-2.5 w-full px-5 py-6 overflow-x-auto snap-x snap-mandatory scroll-smooth bg-tgl11-film bg-[repeating-linear-gradient(90deg,#0a0a0a_0_14px,#1c1c1c_14px_22px,#0a0a0a_22px_36px),repeating-linear-gradient(90deg,#0a0a0a_0_14px,#1c1c1c_14px_22px,#0a0a0a_22px_36px)] [background-size:36px_12px,36px_12px] [background-position:0_6px,0_calc(100%-6px)] bg-repeat-x focus-visible:outline-3 focus-visible:outline-tgl11-acc focus-visible:-outline-offset-[3px] motion-reduce:[scroll-behavior:auto]">
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1483058712412-4245e9b90334?q=80&w=500&h=340&auto=format&fit=crop" alt="Market street in Lisbon" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e?q=80&w=500&h=340&auto=format&fit=crop" alt="Backstreet in the old town" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1505142468610-359e7d316be0?q=80&w=500&h=340&auto=format&fit=crop" alt="Hillside in early summer" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1511499767150-a48a237f0083?q=80&w=500&h=340&auto=format&fit=crop" alt="Concrete stairwell" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1457369804613-52c61a468e7d?q=80&w=500&h=340&auto=format&fit=crop" alt="Lunch at a roadside table" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?q=80&w=500&h=340&auto=format&fit=crop" alt="Empty beach at low tide" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1450101499163-c8848c66ca85?q=80&w=500&h=340&auto=format&fit=crop" alt="Fruit stall at the market" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1518495973542-4542c06a5843?q=80&w=500&h=340&auto=format&fit=crop" alt="Pass road above the treeline" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
</div>
</section><section class="tgl-11 w-full min-h-svh grid place-items-center bg-tgl11-bg font-tgl11-sans py-10" aria-label="Filmstrip carousel gallery">
<div tabindex="0" role="region" aria-label="Scrollable filmstrip, use arrow keys" class="flex gap-2.5 w-full px-5 py-6 overflow-x-auto snap-x snap-mandatory scroll-smooth bg-tgl11-film bg-[repeating-linear-gradient(90deg,#0a0a0a_0_14px,#1c1c1c_14px_22px,#0a0a0a_22px_36px),repeating-linear-gradient(90deg,#0a0a0a_0_14px,#1c1c1c_14px_22px,#0a0a0a_22px_36px)] [background-size:36px_12px,36px_12px] [background-position:0_6px,0_calc(100%-6px)] bg-repeat-x focus-visible:outline-3 focus-visible:outline-tgl11-acc focus-visible:-outline-offset-[3px] motion-reduce:[scroll-behavior:auto]">
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1483058712412-4245e9b90334?q=80&w=500&h=340&auto=format&fit=crop" alt="Market street in Lisbon" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e?q=80&w=500&h=340&auto=format&fit=crop" alt="Backstreet in the old town" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1505142468610-359e7d316be0?q=80&w=500&h=340&auto=format&fit=crop" alt="Hillside in early summer" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1511499767150-a48a237f0083?q=80&w=500&h=340&auto=format&fit=crop" alt="Concrete stairwell" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1457369804613-52c61a468e7d?q=80&w=500&h=340&auto=format&fit=crop" alt="Lunch at a roadside table" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?q=80&w=500&h=340&auto=format&fit=crop" alt="Empty beach at low tide" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1450101499163-c8848c66ca85?q=80&w=500&h=340&auto=format&fit=crop" alt="Fruit stall at the market" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1518495973542-4542c06a5843?q=80&w=500&h=340&auto=format&fit=crop" alt="Pass road above the treeline" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
</div>
</section>@import "tailwindcss";
@theme {
--color-tgl11-bg: #111111;
--color-tgl11-bg: oklch(0.18 0 0);
--color-tgl11-film: #0a0a0a;
--color-tgl11-film: oklch(0.13 0 0);
--color-tgl11-frame: #e8e8e8;
--color-tgl11-frame: oklch(0.93 0 0);
--color-tgl11-acc: #d8b23c;
--color-tgl11-acc: oklch(0.78 0.14 90);
--font-tgl11-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tgl-11 {
width: 100%;
min-height: 100svh;
}
/* Scrollbar styling has no variant form — it stays CSS. */
.tgl-11 [role="region"] {
scrollbar-width: thin;
scrollbar-color: var(--color-tgl11-acc) #222;
}
.tgl-11 [role="region"]::-webkit-scrollbar {
height: 8px;
}
.tgl-11 [role="region"]::-webkit-scrollbar-thumb {
background: var(--color-tgl11-acc);
border-radius: 8px;
}
.tgl-11 ::selection {
background: var(--color-tgl11-acc);
color: #111;
}@import "tailwindcss";
@theme {
--color-tgl11-bg: #111111;
--color-tgl11-bg: oklch(0.18 0 0);
--color-tgl11-film: #0a0a0a;
--color-tgl11-film: oklch(0.13 0 0);
--color-tgl11-frame: #e8e8e8;
--color-tgl11-frame: oklch(0.93 0 0);
--color-tgl11-acc: #d8b23c;
--color-tgl11-acc: oklch(0.78 0.14 90);
--font-tgl11-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tgl-11 {
width: 100%;
min-height: 100svh;
}
/* Scrollbar styling has no variant form — it stays CSS. */
.tgl-11 [role="region"] {
scrollbar-width: thin;
scrollbar-color: var(--color-tgl11-acc) #222;
}
.tgl-11 [role="region"]::-webkit-scrollbar {
height: 8px;
}
.tgl-11 [role="region"]::-webkit-scrollbar-thumb {
background: var(--color-tgl11-acc);
border-radius: 8px;
}
.tgl-11 ::selection {
background: var(--color-tgl11-acc);
color: #111;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<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.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-tgl11-bg: #111111;
--color-tgl11-bg: oklch(0.18 0 0);
--color-tgl11-film: #0a0a0a;
--color-tgl11-film: oklch(0.13 0 0);
--color-tgl11-frame: #e8e8e8;
--color-tgl11-frame: oklch(0.93 0 0);
--color-tgl11-acc: #d8b23c;
--color-tgl11-acc: oklch(0.78 0.14 90);
--font-tgl11-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tgl-11 {
width: 100%;
min-height: 100svh;
}
/* Scrollbar styling has no variant form — it stays CSS. */
.tgl-11 [role="region"] {
scrollbar-width: thin;
scrollbar-color: var(--color-tgl11-acc) #222;
}
.tgl-11 [role="region"]::-webkit-scrollbar {
height: 8px;
}
.tgl-11 [role="region"]::-webkit-scrollbar-thumb {
background: var(--color-tgl11-acc);
border-radius: 8px;
}
.tgl-11 ::selection {
background: var(--color-tgl11-acc);
color: #111;
}@import "tailwindcss";
@theme {
--color-tgl11-bg: #111111;
--color-tgl11-bg: oklch(0.18 0 0);
--color-tgl11-film: #0a0a0a;
--color-tgl11-film: oklch(0.13 0 0);
--color-tgl11-frame: #e8e8e8;
--color-tgl11-frame: oklch(0.93 0 0);
--color-tgl11-acc: #d8b23c;
--color-tgl11-acc: oklch(0.78 0.14 90);
--font-tgl11-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tgl-11 {
width: 100%;
min-height: 100svh;
}
/* Scrollbar styling has no variant form — it stays CSS. */
.tgl-11 [role="region"] {
scrollbar-width: thin;
scrollbar-color: var(--color-tgl11-acc) #222;
}
.tgl-11 [role="region"]::-webkit-scrollbar {
height: 8px;
}
.tgl-11 [role="region"]::-webkit-scrollbar-thumb {
background: var(--color-tgl11-acc);
border-radius: 8px;
}
.tgl-11 ::selection {
background: var(--color-tgl11-acc);
color: #111;
}<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">
<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.
- The snap family is the clearest case in the collection of Tailwind shipping exactly the right utilities: scroll-snap is a design decision made per element, and every part of it has a class.
- The sprocket gradients stay inline as arbitrary values even though they are long, because they belong to this strip alone; a
@themeentry would imply reuse that will never happen. - UI change from the CSS original: alt text is now specific per frame instead of "Travel photo 4", and the hover restores contrast as well as colour so the change reads on a monochrome display too.
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 Filmstrip Carousel Gallery with CSS Scroll-Snap
Source: https://codefronts.com/snippets/tailwind-css-image-gallery/tailwind-filmstrip-carousel-gallery-scroll-snap/
A low-profile strip of thumbnails that scrolls and snaps like a camera filmstrip, sprocket holes included. Tailwind ships the whole snap family as utilities, so the carousel — normally a library — is five classes on a container and one on each frame.
## HTML
```html
<section class="tgl-11 w-full min-h-svh grid place-items-center bg-tgl11-bg font-tgl11-sans py-10" aria-label="Filmstrip carousel gallery">
<div tabindex="0" role="region" aria-label="Scrollable filmstrip, use arrow keys" class="flex gap-2.5 w-full px-5 py-6 overflow-x-auto snap-x snap-mandatory scroll-smooth bg-tgl11-film bg-[repeating-linear-gradient(90deg,#0a0a0a_0_14px,#1c1c1c_14px_22px,#0a0a0a_22px_36px),repeating-linear-gradient(90deg,#0a0a0a_0_14px,#1c1c1c_14px_22px,#0a0a0a_22px_36px)] [background-size:36px_12px,36px_12px] [background-position:0_6px,0_calc(100%-6px)] bg-repeat-x focus-visible:outline-3 focus-visible:outline-tgl11-acc focus-visible:-outline-offset-[3px] motion-reduce:[scroll-behavior:auto]">
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1483058712412-4245e9b90334?q=80&w=500&h=340&auto=format&fit=crop" alt="Market street in Lisbon" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e?q=80&w=500&h=340&auto=format&fit=crop" alt="Backstreet in the old town" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1505142468610-359e7d316be0?q=80&w=500&h=340&auto=format&fit=crop" alt="Hillside in early summer" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1511499767150-a48a237f0083?q=80&w=500&h=340&auto=format&fit=crop" alt="Concrete stairwell" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1457369804613-52c61a468e7d?q=80&w=500&h=340&auto=format&fit=crop" alt="Lunch at a roadside table" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?q=80&w=500&h=340&auto=format&fit=crop" alt="Empty beach at low tide" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1450101499163-c8848c66ca85?q=80&w=500&h=340&auto=format&fit=crop" alt="Fruit stall at the market" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1518495973542-4542c06a5843?q=80&w=500&h=340&auto=format&fit=crop" alt="Pass road above the treeline" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tgl11-bg: #111111;
--color-tgl11-bg: oklch(0.18 0 0);
--color-tgl11-film: #0a0a0a;
--color-tgl11-film: oklch(0.13 0 0);
--color-tgl11-frame: #e8e8e8;
--color-tgl11-frame: oklch(0.93 0 0);
--color-tgl11-acc: #d8b23c;
--color-tgl11-acc: oklch(0.78 0.14 90);
--font-tgl11-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tgl-11 {
width: 100%;
min-height: 100svh;
}
/* Scrollbar styling has no variant form — it stays CSS. */
.tgl-11 [role="region"] {
scrollbar-width: thin;
scrollbar-color: var(--color-tgl11-acc) #222;
}
.tgl-11 [role="region"]::-webkit-scrollbar {
height: 8px;
}
.tgl-11 [role="region"]::-webkit-scrollbar-thumb {
background: var(--color-tgl11-acc);
border-radius: 8px;
}
.tgl-11 ::selection {
background: var(--color-tgl11-acc);
color: #111;
}
```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 Filmstrip Carousel Gallery with CSS Scroll-Snap
Source: https://codefronts.com/snippets/tailwind-css-image-gallery/tailwind-filmstrip-carousel-gallery-scroll-snap/
A low-profile strip of thumbnails that scrolls and snaps like a camera filmstrip, sprocket holes included. Tailwind ships the whole snap family as utilities, so the carousel — normally a library — is five classes on a container and one on each frame.
## HTML
```html
<section class="tgl-11 w-full min-h-svh grid place-items-center bg-tgl11-bg font-tgl11-sans py-10" aria-label="Filmstrip carousel gallery">
<div tabindex="0" role="region" aria-label="Scrollable filmstrip, use arrow keys" class="flex gap-2.5 w-full px-5 py-6 overflow-x-auto snap-x snap-mandatory scroll-smooth bg-tgl11-film bg-[repeating-linear-gradient(90deg,#0a0a0a_0_14px,#1c1c1c_14px_22px,#0a0a0a_22px_36px),repeating-linear-gradient(90deg,#0a0a0a_0_14px,#1c1c1c_14px_22px,#0a0a0a_22px_36px)] [background-size:36px_12px,36px_12px] [background-position:0_6px,0_calc(100%-6px)] bg-repeat-x focus-visible:outline-3 focus-visible:outline-tgl11-acc focus-visible:-outline-offset-[3px] motion-reduce:[scroll-behavior:auto]">
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1483058712412-4245e9b90334?q=80&w=500&h=340&auto=format&fit=crop" alt="Market street in Lisbon" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1573497019940-1c28c88b4f3e?q=80&w=500&h=340&auto=format&fit=crop" alt="Backstreet in the old town" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1505142468610-359e7d316be0?q=80&w=500&h=340&auto=format&fit=crop" alt="Hillside in early summer" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1511499767150-a48a237f0083?q=80&w=500&h=340&auto=format&fit=crop" alt="Concrete stairwell" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1457369804613-52c61a468e7d?q=80&w=500&h=340&auto=format&fit=crop" alt="Lunch at a roadside table" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?q=80&w=500&h=340&auto=format&fit=crop" alt="Empty beach at low tide" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1450101499163-c8848c66ca85?q=80&w=500&h=340&auto=format&fit=crop" alt="Fruit stall at the market" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
<figure class="group m-0 flex-[0_0_auto] w-[min(340px,72vw)] snap-center border-[3px] border-tgl11-frame rounded-sm bg-tgl11-frame overflow-hidden"><img src="https://images.unsplash.com/photo-1518495973542-4542c06a5843?q=80&w=500&h=340&auto=format&fit=crop" alt="Pass road above the treeline" loading="lazy" decoding="async" class="block w-full [aspect-ratio:3/2] object-cover grayscale-[0.1] contrast-[1.02] transition-[filter] duration-300 group-hover:grayscale-0 group-hover:contrast-100 motion-reduce:transition-none"></figure>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tgl11-bg: #111111;
--color-tgl11-bg: oklch(0.18 0 0);
--color-tgl11-film: #0a0a0a;
--color-tgl11-film: oklch(0.13 0 0);
--color-tgl11-frame: #e8e8e8;
--color-tgl11-frame: oklch(0.93 0 0);
--color-tgl11-acc: #d8b23c;
--color-tgl11-acc: oklch(0.78 0.14 90);
--font-tgl11-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tgl-11 {
width: 100%;
min-height: 100svh;
}
/* Scrollbar styling has no variant form — it stays CSS. */
.tgl-11 [role="region"] {
scrollbar-width: thin;
scrollbar-color: var(--color-tgl11-acc) #222;
}
.tgl-11 [role="region"]::-webkit-scrollbar {
height: 8px;
}
.tgl-11 [role="region"]::-webkit-scrollbar-thumb {
background: var(--color-tgl11-acc);
border-radius: 8px;
}
.tgl-11 ::selection {
background: var(--color-tgl11-acc);
color: #111;
}
```How this works
Snap is a design-scale feature, so Tailwind ships it. snap-x, snap-mandatory and snap-center map one to one onto the CSS, and the result is a carousel with native momentum, native keyboard scrolling and no library:
<div tabindex="0" role="region" class="flex gap-2.5 overflow-x-auto snap-x snap-mandatory">The film is decoration, and it stays in the class list. Two repeating gradients pinned top and bottom paint the sprocket holes; the sizes and positions are arbitrary properties because 36×12px is film geometry, not a spacing scale.
Scrollbar styling is the one thing that must stay CSS. ::-webkit-scrollbar has no variant form, so it lives in the stylesheet with scrollbar-width/scrollbar-color beside it.
Make it yours
- Frame size:
w-[min(340px,72vw)]on each frame — smaller frames show more strip. - Alignment:
snap-startfor a left-aligned feed instead of centred. - Delete the two gradient utilities for a clean modern thumbnail rail with the same snapping.
Gotchas — read before shipping
- A scroll container needs
tabindex="0"and a visible focus style, or keyboard users cannot scroll it at all — this is the most-missed part of every snap carousel. snap-mandatoryis right for a short horizontal strip; usesnap-proximityfor long or variable-height feeds.- Fix the frame width so lazy-loaded images cannot collapse the strip mid-scroll.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
CSS scroll-snap is universal; the floor is Tailwind v4's generated sheet. ::scroll-button controls are progressive enhancement (Chrome 135+).