Pure TailwindMIT licensed

Tailwind Expanding Panel Image Gallery with Flex-Grow Transitions

A full-bleed split of tall panels that slide open from flex:1 to flex:5 on hover or keyboard focus, revealing a title, blurb and call-to-action over the photograph. The immersive case-study index, ported so that the open state and the copy reveal are declared on the elements they affect.

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-03 w-full min-h-svh flex items-stretch bg-tgl03-bg font-tgl03-sans" aria-label="Expanding panel gallery">
  <div class="flex w-full min-h-svh">
    <a href="#" style="--img:url('https://images.unsplash.com/photo-1600210492486-724fe5c67fb0?q=80&w=900&h=1100&auto=format&fit=crop')" class="group relative flex-[1_1_0] min-w-0 overflow-hidden no-underline bg-[image:var(--img)] bg-cover bg-center brightness-[0.62] transition-[flex,filter] duration-[600ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:flex-[5_1_0] hover:brightness-100 focus-within:flex-[5_1_0] focus-within:brightness-100 focus-visible:outline-3 focus-visible:outline-tgl03-acc focus-visible:-outline-offset-[3px] motion-reduce:transition-none">
      <span aria-hidden="true" class="absolute inset-0 bg-[linear-gradient(0deg,oklch(0.15_0.02_265/0.85),transparent_60%)]"></span>
      <span class="absolute left-0 right-0 top-6 z-[2] text-center text-[11px] font-bold tracking-[0.18em] uppercase text-white/70 transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0">Structures</span>
      <div class="absolute left-0 right-0 bottom-0 z-[2] p-8 max-w-[520px] text-white opacity-0 translate-y-6 transition-[opacity,translate] duration-500 delay-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:opacity-100 group-focus-within:translate-y-0 motion-reduce:transition-none">
        <h3 class="text-[30px] font-bold tracking-[-0.01em] m-0">Structures</h3>
        <p class="mt-2 text-[15px] leading-[1.5] text-white/85">Concrete, glass and the geometry of modern cities.</p>
        <span class="inline-block mt-3.5 text-[13px] font-bold tracking-[0.04em] text-tgl03-acc">View series &rarr;</span>
      </div>
    </a>
    <a href="#" style="--img:url('https://images.unsplash.com/photo-1524995997946-a1c2e315a42f?q=80&w=900&h=1100&auto=format&fit=crop')" class="group relative flex-[1_1_0] min-w-0 overflow-hidden no-underline bg-[image:var(--img)] bg-cover bg-center brightness-[0.62] transition-[flex,filter] duration-[600ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:flex-[5_1_0] hover:brightness-100 focus-within:flex-[5_1_0] focus-within:brightness-100 focus-visible:outline-3 focus-visible:outline-tgl03-acc focus-visible:-outline-offset-[3px] motion-reduce:transition-none">
      <span aria-hidden="true" class="absolute inset-0 bg-[linear-gradient(0deg,oklch(0.15_0.02_265/0.85),transparent_60%)]"></span>
      <span class="absolute left-0 right-0 top-6 z-[2] text-center text-[11px] font-bold tracking-[0.18em] uppercase text-white/70 transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0">Wilderness</span>
      <div class="absolute left-0 right-0 bottom-0 z-[2] p-8 max-w-[520px] text-white opacity-0 translate-y-6 transition-[opacity,translate] duration-500 delay-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:opacity-100 group-focus-within:translate-y-0 motion-reduce:transition-none">
        <h3 class="text-[30px] font-bold tracking-[-0.01em] m-0">Wilderness</h3>
        <p class="mt-2 text-[15px] leading-[1.5] text-white/85">Remote landscapes far from the nearest road.</p>
        <span class="inline-block mt-3.5 text-[13px] font-bold tracking-[0.04em] text-tgl03-acc">View series &rarr;</span>
      </div>
    </a>
    <a href="#" style="--img:url('https://images.unsplash.com/photo-1600185365483-26d7a4cc7519?q=80&w=900&h=1100&auto=format&fit=crop')" class="group relative flex-[1_1_0] min-w-0 overflow-hidden no-underline bg-[image:var(--img)] bg-cover bg-center brightness-[0.62] transition-[flex,filter] duration-[600ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:flex-[5_1_0] hover:brightness-100 focus-within:flex-[5_1_0] focus-within:brightness-100 focus-visible:outline-3 focus-visible:outline-tgl03-acc focus-visible:-outline-offset-[3px] motion-reduce:transition-none">
      <span aria-hidden="true" class="absolute inset-0 bg-[linear-gradient(0deg,oklch(0.15_0.02_265/0.85),transparent_60%)]"></span>
      <span class="absolute left-0 right-0 top-6 z-[2] text-center text-[11px] font-bold tracking-[0.18em] uppercase text-white/70 transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0">Portraits</span>
      <div class="absolute left-0 right-0 bottom-0 z-[2] p-8 max-w-[520px] text-white opacity-0 translate-y-6 transition-[opacity,translate] duration-500 delay-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:opacity-100 group-focus-within:translate-y-0 motion-reduce:transition-none">
        <h3 class="text-[30px] font-bold tracking-[-0.01em] m-0">Portraits</h3>
        <p class="mt-2 text-[15px] leading-[1.5] text-white/85">Faces and the stories written across them.</p>
        <span class="inline-block mt-3.5 text-[13px] font-bold tracking-[0.04em] text-tgl03-acc">View series &rarr;</span>
      </div>
    </a>
    <a href="#" style="--img:url('https://images.unsplash.com/photo-1529107386315-e1a2ed48a620?q=80&w=900&h=1100&auto=format&fit=crop')" class="group relative flex-[1_1_0] min-w-0 overflow-hidden no-underline bg-[image:var(--img)] bg-cover bg-center brightness-[0.62] transition-[flex,filter] duration-[600ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:flex-[5_1_0] hover:brightness-100 focus-within:flex-[5_1_0] focus-within:brightness-100 focus-visible:outline-3 focus-visible:outline-tgl03-acc focus-visible:-outline-offset-[3px] motion-reduce:transition-none">
      <span aria-hidden="true" class="absolute inset-0 bg-[linear-gradient(0deg,oklch(0.15_0.02_265/0.85),transparent_60%)]"></span>
      <span class="absolute left-0 right-0 top-6 z-[2] text-center text-[11px] font-bold tracking-[0.18em] uppercase text-white/70 transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0">Water</span>
      <div class="absolute left-0 right-0 bottom-0 z-[2] p-8 max-w-[520px] text-white opacity-0 translate-y-6 transition-[opacity,translate] duration-500 delay-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:opacity-100 group-focus-within:translate-y-0 motion-reduce:transition-none">
        <h3 class="text-[30px] font-bold tracking-[-0.01em] m-0">Water</h3>
        <p class="mt-2 text-[15px] leading-[1.5] text-white/85">Oceans, rivers and everything in between.</p>
        <span class="inline-block mt-3.5 text-[13px] font-bold tracking-[0.04em] text-tgl03-acc">View series &rarr;</span>
      </div>
    </a>
    <a href="#" style="--img:url('https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?q=80&w=900&h=1100&auto=format&fit=crop')" class="group relative flex-[1_1_0] min-w-0 overflow-hidden no-underline bg-[image:var(--img)] bg-cover bg-center brightness-[0.62] transition-[flex,filter] duration-[600ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:flex-[5_1_0] hover:brightness-100 focus-within:flex-[5_1_0] focus-within:brightness-100 focus-visible:outline-3 focus-visible:outline-tgl03-acc focus-visible:-outline-offset-[3px] motion-reduce:transition-none">
      <span aria-hidden="true" class="absolute inset-0 bg-[linear-gradient(0deg,oklch(0.15_0.02_265/0.85),transparent_60%)]"></span>
      <span class="absolute left-0 right-0 top-6 z-[2] text-center text-[11px] font-bold tracking-[0.18em] uppercase text-white/70 transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0">After Dark</span>
      <div class="absolute left-0 right-0 bottom-0 z-[2] p-8 max-w-[520px] text-white opacity-0 translate-y-6 transition-[opacity,translate] duration-500 delay-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:opacity-100 group-focus-within:translate-y-0 motion-reduce:transition-none">
        <h3 class="text-[30px] font-bold tracking-[-0.01em] m-0">After Dark</h3>
        <p class="mt-2 text-[15px] leading-[1.5] text-white/85">Long exposures under a moving sky.</p>
        <span class="inline-block mt-3.5 text-[13px] font-bold tracking-[0.04em] text-tgl03-acc">View series &rarr;</span>
      </div>
    </a>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tgl03-bg: #0c0e12;
  --color-tgl03-bg: oklch(0.14 0.012 265);
  --color-tgl03-acc: #6fa8ff;
  --color-tgl03-acc: oklch(0.75 0.14 250);
  --font-tgl03-sans: 'Space Grotesk', system-ui, sans-serif;
}

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

.tgl-03 ::selection {
  background: var(--color-tgl03-acc);
  color: #0c0e12;
}

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-tgl03-bg: #0c0e12;
  --color-tgl03-bg: oklch(0.14 0.012 265);
  --color-tgl03-acc: #6fa8ff;
  --color-tgl03-acc: oklch(0.75 0.14 250);
  --font-tgl03-sans: 'Space Grotesk', system-ui, sans-serif;
}

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

.tgl-03 ::selection {
  background: var(--color-tgl03-acc);
  color: #0c0e12;
}
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.

  • hover: and focus-within: sit adjacent in the class list, which is the strongest argument for the port: the keyboard path is now impossible to overlook.
  • The resting dim moved from a stacked overlay to brightness-[0.62], one utility that also animates on the compositor.
  • UI change from the CSS original: collapsed panels now carry a small vertical label that fades out as the panel opens. The original showed five unlabelled photographs, so nothing told a touch user what they were about to open.
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 Expanding Panel Image Gallery with Flex-Grow Transitions
Source: https://codefronts.com/snippets/tailwind-css-image-gallery/tailwind-expanding-panel-image-gallery-flex-grow/

A full-bleed split of tall panels that slide open from flex:1 to flex:5 on hover or keyboard focus, revealing a title, blurb and call-to-action over the photograph. The immersive case-study index, ported so that the open state and the copy reveal are declared on the elements they affect.
## HTML
```html
<section class="tgl-03 w-full min-h-svh flex items-stretch bg-tgl03-bg font-tgl03-sans" aria-label="Expanding panel gallery">
  <div class="flex w-full min-h-svh">
    <a href="#" style="--img:url('https://images.unsplash.com/photo-1600210492486-724fe5c67fb0?q=80&w=900&h=1100&auto=format&fit=crop')" class="group relative flex-[1_1_0] min-w-0 overflow-hidden no-underline bg-[image:var(--img)] bg-cover bg-center brightness-[0.62] transition-[flex,filter] duration-[600ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:flex-[5_1_0] hover:brightness-100 focus-within:flex-[5_1_0] focus-within:brightness-100 focus-visible:outline-3 focus-visible:outline-tgl03-acc focus-visible:-outline-offset-[3px] motion-reduce:transition-none">
      <span aria-hidden="true" class="absolute inset-0 bg-[linear-gradient(0deg,oklch(0.15_0.02_265/0.85),transparent_60%)]"></span>
      <span class="absolute left-0 right-0 top-6 z-[2] text-center text-[11px] font-bold tracking-[0.18em] uppercase text-white/70 transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0">Structures</span>
      <div class="absolute left-0 right-0 bottom-0 z-[2] p-8 max-w-[520px] text-white opacity-0 translate-y-6 transition-[opacity,translate] duration-500 delay-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:opacity-100 group-focus-within:translate-y-0 motion-reduce:transition-none">
        <h3 class="text-[30px] font-bold tracking-[-0.01em] m-0">Structures</h3>
        <p class="mt-2 text-[15px] leading-[1.5] text-white/85">Concrete, glass and the geometry of modern cities.</p>
        <span class="inline-block mt-3.5 text-[13px] font-bold tracking-[0.04em] text-tgl03-acc">View series &rarr;</span>
      </div>
    </a>
    <a href="#" style="--img:url('https://images.unsplash.com/photo-1524995997946-a1c2e315a42f?q=80&w=900&h=1100&auto=format&fit=crop')" class="group relative flex-[1_1_0] min-w-0 overflow-hidden no-underline bg-[image:var(--img)] bg-cover bg-center brightness-[0.62] transition-[flex,filter] duration-[600ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:flex-[5_1_0] hover:brightness-100 focus-within:flex-[5_1_0] focus-within:brightness-100 focus-visible:outline-3 focus-visible:outline-tgl03-acc focus-visible:-outline-offset-[3px] motion-reduce:transition-none">
      <span aria-hidden="true" class="absolute inset-0 bg-[linear-gradient(0deg,oklch(0.15_0.02_265/0.85),transparent_60%)]"></span>
      <span class="absolute left-0 right-0 top-6 z-[2] text-center text-[11px] font-bold tracking-[0.18em] uppercase text-white/70 transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0">Wilderness</span>
      <div class="absolute left-0 right-0 bottom-0 z-[2] p-8 max-w-[520px] text-white opacity-0 translate-y-6 transition-[opacity,translate] duration-500 delay-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:opacity-100 group-focus-within:translate-y-0 motion-reduce:transition-none">
        <h3 class="text-[30px] font-bold tracking-[-0.01em] m-0">Wilderness</h3>
        <p class="mt-2 text-[15px] leading-[1.5] text-white/85">Remote landscapes far from the nearest road.</p>
        <span class="inline-block mt-3.5 text-[13px] font-bold tracking-[0.04em] text-tgl03-acc">View series &rarr;</span>
      </div>
    </a>
    <a href="#" style="--img:url('https://images.unsplash.com/photo-1600185365483-26d7a4cc7519?q=80&w=900&h=1100&auto=format&fit=crop')" class="group relative flex-[1_1_0] min-w-0 overflow-hidden no-underline bg-[image:var(--img)] bg-cover bg-center brightness-[0.62] transition-[flex,filter] duration-[600ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:flex-[5_1_0] hover:brightness-100 focus-within:flex-[5_1_0] focus-within:brightness-100 focus-visible:outline-3 focus-visible:outline-tgl03-acc focus-visible:-outline-offset-[3px] motion-reduce:transition-none">
      <span aria-hidden="true" class="absolute inset-0 bg-[linear-gradient(0deg,oklch(0.15_0.02_265/0.85),transparent_60%)]"></span>
      <span class="absolute left-0 right-0 top-6 z-[2] text-center text-[11px] font-bold tracking-[0.18em] uppercase text-white/70 transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0">Portraits</span>
      <div class="absolute left-0 right-0 bottom-0 z-[2] p-8 max-w-[520px] text-white opacity-0 translate-y-6 transition-[opacity,translate] duration-500 delay-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:opacity-100 group-focus-within:translate-y-0 motion-reduce:transition-none">
        <h3 class="text-[30px] font-bold tracking-[-0.01em] m-0">Portraits</h3>
        <p class="mt-2 text-[15px] leading-[1.5] text-white/85">Faces and the stories written across them.</p>
        <span class="inline-block mt-3.5 text-[13px] font-bold tracking-[0.04em] text-tgl03-acc">View series &rarr;</span>
      </div>
    </a>
    <a href="#" style="--img:url('https://images.unsplash.com/photo-1529107386315-e1a2ed48a620?q=80&w=900&h=1100&auto=format&fit=crop')" class="group relative flex-[1_1_0] min-w-0 overflow-hidden no-underline bg-[image:var(--img)] bg-cover bg-center brightness-[0.62] transition-[flex,filter] duration-[600ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:flex-[5_1_0] hover:brightness-100 focus-within:flex-[5_1_0] focus-within:brightness-100 focus-visible:outline-3 focus-visible:outline-tgl03-acc focus-visible:-outline-offset-[3px] motion-reduce:transition-none">
      <span aria-hidden="true" class="absolute inset-0 bg-[linear-gradient(0deg,oklch(0.15_0.02_265/0.85),transparent_60%)]"></span>
      <span class="absolute left-0 right-0 top-6 z-[2] text-center text-[11px] font-bold tracking-[0.18em] uppercase text-white/70 transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0">Water</span>
      <div class="absolute left-0 right-0 bottom-0 z-[2] p-8 max-w-[520px] text-white opacity-0 translate-y-6 transition-[opacity,translate] duration-500 delay-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:opacity-100 group-focus-within:translate-y-0 motion-reduce:transition-none">
        <h3 class="text-[30px] font-bold tracking-[-0.01em] m-0">Water</h3>
        <p class="mt-2 text-[15px] leading-[1.5] text-white/85">Oceans, rivers and everything in between.</p>
        <span class="inline-block mt-3.5 text-[13px] font-bold tracking-[0.04em] text-tgl03-acc">View series &rarr;</span>
      </div>
    </a>
    <a href="#" style="--img:url('https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?q=80&w=900&h=1100&auto=format&fit=crop')" class="group relative flex-[1_1_0] min-w-0 overflow-hidden no-underline bg-[image:var(--img)] bg-cover bg-center brightness-[0.62] transition-[flex,filter] duration-[600ms] ease-[cubic-bezier(0.2,0.7,0.2,1)] hover:flex-[5_1_0] hover:brightness-100 focus-within:flex-[5_1_0] focus-within:brightness-100 focus-visible:outline-3 focus-visible:outline-tgl03-acc focus-visible:-outline-offset-[3px] motion-reduce:transition-none">
      <span aria-hidden="true" class="absolute inset-0 bg-[linear-gradient(0deg,oklch(0.15_0.02_265/0.85),transparent_60%)]"></span>
      <span class="absolute left-0 right-0 top-6 z-[2] text-center text-[11px] font-bold tracking-[0.18em] uppercase text-white/70 transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0">After Dark</span>
      <div class="absolute left-0 right-0 bottom-0 z-[2] p-8 max-w-[520px] text-white opacity-0 translate-y-6 transition-[opacity,translate] duration-500 delay-150 group-hover:opacity-100 group-hover:translate-y-0 group-focus-within:opacity-100 group-focus-within:translate-y-0 motion-reduce:transition-none">
        <h3 class="text-[30px] font-bold tracking-[-0.01em] m-0">After Dark</h3>
        <p class="mt-2 text-[15px] leading-[1.5] text-white/85">Long exposures under a moving sky.</p>
        <span class="inline-block mt-3.5 text-[13px] font-bold tracking-[0.04em] text-tgl03-acc">View series &rarr;</span>
      </div>
    </a>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tgl03-bg: #0c0e12;
  --color-tgl03-bg: oklch(0.14 0.012 265);
  --color-tgl03-acc: #6fa8ff;
  --color-tgl03-acc: oklch(0.75 0.14 250);
  --font-tgl03-sans: 'Space Grotesk', system-ui, sans-serif;
}

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

.tgl-03 ::selection {
  background: var(--color-tgl03-acc);
  color: #0c0e12;
}
```

How this works

The open state is two utilities. Five panels share the row at flex-[1_1_0]; the interacted one jumps to flex-[5_1_0] and the rest absorb the loss. Stating hover: and focus-within: side by side is the port's quiet accessibility win — in CSS they were a comma-joined selector far from the panel, and the second half is exactly the half that gets dropped in a refactor.

The copy reveal is a group, delayed. The panel is group; the inner block carries opacity-0 translate-y-6 at rest and group-hover:/group-focus-within: the opposite, with delay-150 so the text does not race the width.

Collapsed panels keep a vertical label, so the row still reads as five destinations before anything is hovered — the original left them blank.

Make it yours

  • Dominance: hover:flex-[5_1_0] is bold, hover:flex-[3_1_0] gentle.
  • Flip to horizontal bands with flex-col on the row and the same grow utilities.
  • Change the reveal pacing with delay-150 / duration-500 on the inner block.

Gotchas — read before shipping

  • Animating flex animates layout — it is the technique here, but keep the panel count at five or six and the easing short.
  • focus-within: must be present on the panel, not just hover:, or keyboard users open a panel they cannot read.
  • Give collapsed panels enough width to stay tappable on touch, where there is no hover at all.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

Flexbox and :focus-within are universal; the floor is Tailwind v4's generated sheet.

Techniques used in this demo

Search CodeFronts

Loading…