08 / 22
All 22 in 22 Tailwind CSS Image Carousel
- 01Tailwind E-commerce Product Gallery Carousel with Thumbnails
- 02Tailwind Shop the Look Multi-Item Card Slider with Scroll Snap
- 03Tailwind Infinite Logo Scroller Marquee with No JavaScript
- 04Tailwind Product Colour Variant Picker Slider
- 05Tailwind Full-Screen Hero Slideshow with Auto Cross-Fade
- 06Tailwind Testimonial Card Carousel with Star Ratings
- 07Tailwind Meet the Team Profile Slider with Circular Portraits
- 08Tailwind Portfolio Gallery Slider with Hover Caption Reveal
- 09Tailwind Netflix-Style Content Row Carousel with Hover Expand
- 10Tailwind Magazine Split-Screen Article Slider
- 11Tailwind Onboarding Slider with Native CSS Scroll-Marker Dots
- 12Tailwind Vertical Image Carousel with Y-Axis Scroll Snap
- 13Tailwind 3D Coverflow Carousel with Perspective Transforms
- 14Tailwind Cross-Fade Image Slideshow with Manual Controls
- 15Tailwind Dual Opposite-Direction Marquee Slider
- 16Tailwind Dot Pagination Carousel with Target and Has Selectors
- 17Tailwind Prev / Next Arrow Carousel with Native Scroll Buttons
- 18Tailwind Before / After Image Comparison Slider
- 19Tailwind Accordion Expanding Image Panel Carousel
- 20Tailwind Autoplay Slider with Keyframe Track and Progress Bars
- 21Tailwind Zoom-on-Hover Image Gallery Slider
- 22Tailwind Parallax Text-Over-Image Story Slider
Tailwind Portfolio Gallery Slider with Hover Caption Reveal
A case-study rail where each screenshot reveals its title and category on hover, sliding up from the bottom edge. Two transforms on two elements, both driven from one group on the link — and the caption is real text, so it is indexable as well as visible.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tcar-08 w-full min-h-svh grid place-items-center bg-tcar08-bg font-tcar08-sans px-3 py-10" aria-label="Selected work">
<ul tabindex="0" role="group" aria-label="Portfolio projects, scrollable" class="list-none flex gap-[18px] w-[min(820px,100%)] overflow-x-auto p-3.5 m-0 snap-x snap-mandatory [scroll-padding:14px] [scrollbar-width:thin] [scrollbar-color:var(--color-tcar08-track)_transparent] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2 focus-visible:rounded-2xl">
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-1/640/800" width="640" height="800" decoding="async" alt="Fintech dashboard redesign" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Product</span><span class="block text-base font-bold text-white">Ledger — Fintech Dashboard</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-2/640/800" width="640" height="800" loading="lazy" decoding="async" alt="Coffee brand identity" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Branding</span><span class="block text-base font-bold text-white">Cùrrent — Coffee Identity</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-3/640/800" width="640" height="800" loading="lazy" decoding="async" alt="Travel app case study" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Mobile</span><span class="block text-base font-bold text-white">Wander — Travel App</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-4/640/800" width="640" height="800" loading="lazy" decoding="async" alt="E-commerce replatform" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Web</span><span class="block text-base font-bold text-white">Maison — E-commerce</span>
</span>
</a>
</li>
</ul>
</section><section class="tcar-08 w-full min-h-svh grid place-items-center bg-tcar08-bg font-tcar08-sans px-3 py-10" aria-label="Selected work">
<ul tabindex="0" role="group" aria-label="Portfolio projects, scrollable" class="list-none flex gap-[18px] w-[min(820px,100%)] overflow-x-auto p-3.5 m-0 snap-x snap-mandatory [scroll-padding:14px] [scrollbar-width:thin] [scrollbar-color:var(--color-tcar08-track)_transparent] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2 focus-visible:rounded-2xl">
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-1/640/800" width="640" height="800" decoding="async" alt="Fintech dashboard redesign" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Product</span><span class="block text-base font-bold text-white">Ledger — Fintech Dashboard</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-2/640/800" width="640" height="800" loading="lazy" decoding="async" alt="Coffee brand identity" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Branding</span><span class="block text-base font-bold text-white">Cùrrent — Coffee Identity</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-3/640/800" width="640" height="800" loading="lazy" decoding="async" alt="Travel app case study" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Mobile</span><span class="block text-base font-bold text-white">Wander — Travel App</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-4/640/800" width="640" height="800" loading="lazy" decoding="async" alt="E-commerce replatform" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Web</span><span class="block text-base font-bold text-white">Maison — E-commerce</span>
</span>
</a>
</li>
</ul>
</section>@import "tailwindcss";
@theme {
--color-tcar08-bg: #111318;
--color-tcar08-bg: oklch(0.19 0.008 265);
--color-tcar08-card: #1a1d24;
--color-tcar08-card: oklch(0.24 0.01 265);
--color-tcar08-track: #333842;
--color-tcar08-track: oklch(0.34 0.012 265);
--color-tcar08-acc: #e6ff4d;
--color-tcar08-acc: oklch(0.94 0.19 115);
--font-tcar08-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tcar-08 {
width: 100%;
min-height: 100svh;
}
.tcar-08 ::selection {
background: var(--color-tcar08-acc);
color: #111;
}
@media (prefers-reduced-motion: reduce) {
.tcar-08 ul {
scroll-behavior: auto;
}
}@import "tailwindcss";
@theme {
--color-tcar08-bg: #111318;
--color-tcar08-bg: oklch(0.19 0.008 265);
--color-tcar08-card: #1a1d24;
--color-tcar08-card: oklch(0.24 0.01 265);
--color-tcar08-track: #333842;
--color-tcar08-track: oklch(0.34 0.012 265);
--color-tcar08-acc: #e6ff4d;
--color-tcar08-acc: oklch(0.94 0.19 115);
--font-tcar08-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tcar-08 {
width: 100%;
min-height: 100svh;
}
.tcar-08 ::selection {
background: var(--color-tcar08-acc);
color: #111;
}
@media (prefers-reduced-motion: reduce) {
.tcar-08 ul {
scroll-behavior: auto;
}
}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-tcar08-bg: #111318;
--color-tcar08-bg: oklch(0.19 0.008 265);
--color-tcar08-card: #1a1d24;
--color-tcar08-card: oklch(0.24 0.01 265);
--color-tcar08-track: #333842;
--color-tcar08-track: oklch(0.34 0.012 265);
--color-tcar08-acc: #e6ff4d;
--color-tcar08-acc: oklch(0.94 0.19 115);
--font-tcar08-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tcar-08 {
width: 100%;
min-height: 100svh;
}
.tcar-08 ::selection {
background: var(--color-tcar08-acc);
color: #111;
}
@media (prefers-reduced-motion: reduce) {
.tcar-08 ul {
scroll-behavior: auto;
}
}@import "tailwindcss";
@theme {
--color-tcar08-bg: #111318;
--color-tcar08-bg: oklch(0.19 0.008 265);
--color-tcar08-card: #1a1d24;
--color-tcar08-card: oklch(0.24 0.01 265);
--color-tcar08-track: #333842;
--color-tcar08-track: oklch(0.34 0.012 265);
--color-tcar08-acc: #e6ff4d;
--color-tcar08-acc: oklch(0.94 0.19 115);
--font-tcar08-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tcar-08 {
width: 100%;
min-height: 100svh;
}
.tcar-08 ::selection {
background: var(--color-tcar08-acc);
color: #111;
}
@media (prefers-reduced-motion: reduce) {
.tcar-08 ul {
scroll-behavior: auto;
}
}<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.
translate-y-fullreplaces the original'stranslateY(101%)hack. The extra 1% existed to hide a subpixel seam; Tailwind's100%plus the frame'soverflow-hiddenmakes it unnecessary.- The reduced-motion branch does not merely disable the transition — it pins the caption open. A caption that animates into view must be visible, not absent, when the animation is off.
- UI change from the CSS original: the link itself gained
focus-visible:outline-3. The original relied on the caption reveal alone to indicate focus, which is invisible to anyone who cannot see the animation and fails WCAG 2.4.7.
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 Portfolio Gallery Slider with Hover Caption Reveal
Source: https://codefronts.com/snippets/tailwind-css-image-carousel/tailwind-portfolio-gallery-hover-caption-reveal/
A case-study rail where each screenshot reveals its title and category on hover, sliding up from the bottom edge. Two transforms on two elements, both driven from one group on the link — and the caption is real text, so it is indexable as well as visible.
## HTML
```html
<section class="tcar-08 w-full min-h-svh grid place-items-center bg-tcar08-bg font-tcar08-sans px-3 py-10" aria-label="Selected work">
<ul tabindex="0" role="group" aria-label="Portfolio projects, scrollable" class="list-none flex gap-[18px] w-[min(820px,100%)] overflow-x-auto p-3.5 m-0 snap-x snap-mandatory [scroll-padding:14px] [scrollbar-width:thin] [scrollbar-color:var(--color-tcar08-track)_transparent] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2 focus-visible:rounded-2xl">
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-1/640/800" width="640" height="800" decoding="async" alt="Fintech dashboard redesign" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Product</span><span class="block text-base font-bold text-white">Ledger — Fintech Dashboard</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-2/640/800" width="640" height="800" loading="lazy" decoding="async" alt="Coffee brand identity" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Branding</span><span class="block text-base font-bold text-white">Cùrrent — Coffee Identity</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-3/640/800" width="640" height="800" loading="lazy" decoding="async" alt="Travel app case study" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Mobile</span><span class="block text-base font-bold text-white">Wander — Travel App</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-4/640/800" width="640" height="800" loading="lazy" decoding="async" alt="E-commerce replatform" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Web</span><span class="block text-base font-bold text-white">Maison — E-commerce</span>
</span>
</a>
</li>
</ul>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcar08-bg: #111318;
--color-tcar08-bg: oklch(0.19 0.008 265);
--color-tcar08-card: #1a1d24;
--color-tcar08-card: oklch(0.24 0.01 265);
--color-tcar08-track: #333842;
--color-tcar08-track: oklch(0.34 0.012 265);
--color-tcar08-acc: #e6ff4d;
--color-tcar08-acc: oklch(0.94 0.19 115);
--font-tcar08-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tcar-08 {
width: 100%;
min-height: 100svh;
}
.tcar-08 ::selection {
background: var(--color-tcar08-acc);
color: #111;
}
@media (prefers-reduced-motion: reduce) {
.tcar-08 ul {
scroll-behavior: auto;
}
}
```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 Portfolio Gallery Slider with Hover Caption Reveal
Source: https://codefronts.com/snippets/tailwind-css-image-carousel/tailwind-portfolio-gallery-hover-caption-reveal/
A case-study rail where each screenshot reveals its title and category on hover, sliding up from the bottom edge. Two transforms on two elements, both driven from one group on the link — and the caption is real text, so it is indexable as well as visible.
## HTML
```html
<section class="tcar-08 w-full min-h-svh grid place-items-center bg-tcar08-bg font-tcar08-sans px-3 py-10" aria-label="Selected work">
<ul tabindex="0" role="group" aria-label="Portfolio projects, scrollable" class="list-none flex gap-[18px] w-[min(820px,100%)] overflow-x-auto p-3.5 m-0 snap-x snap-mandatory [scroll-padding:14px] [scrollbar-width:thin] [scrollbar-color:var(--color-tcar08-track)_transparent] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2 focus-visible:rounded-2xl">
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-1/640/800" width="640" height="800" decoding="async" alt="Fintech dashboard redesign" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Product</span><span class="block text-base font-bold text-white">Ledger — Fintech Dashboard</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-2/640/800" width="640" height="800" loading="lazy" decoding="async" alt="Coffee brand identity" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Branding</span><span class="block text-base font-bold text-white">Cùrrent — Coffee Identity</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-3/640/800" width="640" height="800" loading="lazy" decoding="async" alt="Travel app case study" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Mobile</span><span class="block text-base font-bold text-white">Wander — Travel App</span>
</span>
</a>
</li>
<li class="flex-none basis-[clamp(220px,72%,260px)] snap-start">
<a href="#" class="group block relative rounded-2xl overflow-hidden no-underline bg-tcar08-card shadow-[0_20px_40px_-30px_oklch(0_0_0/0.9)] focus-visible:outline-3 focus-visible:outline-tcar08-acc focus-visible:outline-offset-2">
<span class="block aspect-[4/5] overflow-hidden"><img src="https://picsum.photos/seed/work-4/640/800" width="640" height="800" loading="lazy" decoding="async" alt="E-commerce replatform" class="size-full object-cover block transition-[scale] duration-500 ease-out group-hover:scale-[1.07] group-focus-visible:scale-[1.07] motion-reduce:transition-none motion-reduce:group-hover:scale-100"></span>
<span class="absolute inset-x-0 bottom-0 px-[18px] pt-11 pb-[18px] bg-[linear-gradient(transparent,oklch(0.14_0.01_265/0.92))] translate-y-full opacity-0 transition-[translate,opacity] duration-400 ease-[cubic-bezier(0.2,0.8,0.2,1)] group-hover:translate-y-0 group-hover:opacity-100 group-focus-within:translate-y-0 group-focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
<span class="inline-block text-[11px] tracking-[0.14em] uppercase text-tcar08-acc mb-1.5">Web</span><span class="block text-base font-bold text-white">Maison — E-commerce</span>
</span>
</a>
</li>
</ul>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcar08-bg: #111318;
--color-tcar08-bg: oklch(0.19 0.008 265);
--color-tcar08-card: #1a1d24;
--color-tcar08-card: oklch(0.24 0.01 265);
--color-tcar08-track: #333842;
--color-tcar08-track: oklch(0.34 0.012 265);
--color-tcar08-acc: #e6ff4d;
--color-tcar08-acc: oklch(0.94 0.19 115);
--font-tcar08-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tcar-08 {
width: 100%;
min-height: 100svh;
}
.tcar-08 ::selection {
background: var(--color-tcar08-acc);
color: #111;
}
@media (prefers-reduced-motion: reduce) {
.tcar-08 ul {
scroll-behavior: auto;
}
}
```How this works
The group is the link, not the card. Putting group on the <a> means group-focus-within: fires when the link itself takes focus, so tabbing through the rail reveals each caption in turn.
Two elements, two speeds. The image scales over 500ms while the caption slides over 400ms on a settle curve. Both animate transform only.
The caption is markup. Category and title are real spans, not content: strings — announced by screen readers and crawled by search engines, which a pseudo-element would not be.
Make it yours
- Reveal direction: the caption's rest transform (
translate-y-full,translate-x-full, or opacity-only). - Zoom strength:
group-hover:scale-[1.07]. - Scrim: the arbitrary gradient on the caption.
- Cards per view: the card's
basis-*.
Gotchas — read before shipping
overflow-hiddenbelongs on the image frame, not the card. On the card it clips the caption as well and the reveal never appears.- Keep the caption in the DOM. A
before:content-['Ledger']caption is invisible to assistive tech and to crawlers — on a portfolio, that is the page's entire value. group-focus-within:is mandatory alongsidegroup-hover:; without it the project titles are unreachable by keyboard.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
:focus-within and scroll-snap are universally supported; the floor quoted is Tailwind v4's generated sheet.