webdevpuneet.com

Hover Expand Gallery — Free HTML CSS JS Accordion Gallery

Hover Expand Gallery · Media · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<div class="he-gallery" id="heGallery">
  <div class="he-panel is-open" style="--g:linear-gradient(160deg,#f97316,#db2777)" data-title="Kyoto">
    <span class="he-cap">Kyoto</span>
  </div>
  <div class="he-panel" style="--g:linear-gradient(160deg,#6366f1,#06b6d4)" data-title="Reykjavik">
    <span class="he-cap">Reykjavik</span>
  </div>
  <div class="he-panel" style="--g:linear-gradient(160deg,#10b981,#84cc16)" data-title="Patagonia">
    <span class="he-cap">Patagonia</span>
  </div>
  <div class="he-panel" style="--g:linear-gradient(160deg,#8b5cf6,#ec4899)" data-title="Marrakesh">
    <span class="he-cap">Marrakesh</span>
  </div>
  <div class="he-panel" style="--g:linear-gradient(160deg,#0ea5e9,#6366f1)" data-title="Lofoten">
    <span class="he-cap">Lofoten</span>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Flex-grow layout
Panels share the row — no pixel widths.
Smooth rebalance
Transitioned flex-grow expands and contracts.
Caption reveal
Label fades in with a slight delay.
Readability overlay
Bottom gradient keeps text legible.
One-class logic
A single is-open class drives everything.
Hover and tap
Works on pointers and touchscreens.
Fully responsive
Adapts to any container width.
Any panel count
Flex math handles however many you add.

About this UI Snippet

Hover Expand Gallery — A Horizontal Flex Accordion

Screenshot of the Hover Expand Gallery snippet rendered live

The hover expand gallery is the horizontal image accordion where hovering a slim panel makes it grow to fill most of the row while its neighbours shrink, revealing a caption as it opens. This snippet builds it with plain HTML, CSS flexbox transitions, and a tiny vanilla JavaScript class toggle — no widths to calculate and no library.

Flex-grow does the layout

All panels live in a flex row and share the available space through flex-grow. At rest every panel has the same grow value; the open panel is given a much larger one (flex-grow: 6 versus 1). Because the panels divide the row proportionally, raising one panel's grow automatically squeezes the others — you never set explicit pixel widths, so the gallery is fully responsive and adapts to any container size. A min-width keeps the collapsed panels wide enough to remain clickable.

Animating an intrinsic property

The expansion is animated by putting a transition on flex-grow itself with an ease-out cubic-bezier, so the panels glide between their collapsed and expanded sizes. Animating flex-grow (rather than width) is what lets the whole row rebalance smoothly in one motion: as the active panel grows, the rest contract in the same frame because they're all sharing the same flexible space.

Revealing the caption

Each panel's caption starts hidden — opacity: 0 and nudged down with translateY — and only animates in when the panel gains the is-open class, with a small delay so the text appears after the panel has begun widening. This staggering makes the label feel like it belongs to the expansion rather than popping in abruptly. A bottom gradient overlay (::after) keeps the white caption readable over any panel colour.

One class, mutually exclusive

The JavaScript is deliberately minimal: an open() function toggles a single is-open class so exactly one panel is expanded at a time, and everything else — sizing, caption reveal, overlay — is driven by CSS from that one class. This keeps the logic trivial and the animation entirely declarative.

Hover and touch

Panels expand on mouseenter for pointer devices and also on click, so the gallery works on touchscreens where there is no hover — a tap opens a panel just as a hover does on desktop. This dual binding is the simple, reliable way to make a hover effect usable everywhere.

Customizing it

Swap the gradient backgrounds for real images via background-image, change the open grow ratio for a more or less dramatic expansion, adjust the timing, or add more panels — the flex math handles any count. Pair it with an image accordion, a photo gallery, or a scroll snap gallery.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSFive colored panels render with one open.
  2. 2
    Hover a panelIt expands and the others shrink smoothly.
  3. 3
    See the captionThe label fades in as the panel opens.
  4. 4
    Tap on mobileA tap opens a panel where hover is absent.
  5. 5
    Use real imagesSet background-image on each panel.
  6. 6
    Tune the spreadChange the open panel's flex-grow ratio.

Real-world uses

Common Use Cases

Travel and portfolio galleries
Offer an expressive alternative to a standard photo gallery, where hovering a slim panel makes it grow while its neighbours shrink.
Feature reveals
Pair with an image accordion to introduce product features one panel at a time, with captions fading in after a slight delay.
Visual category pickers
Place above a scroll snap gallery as a navigation band, where each panel represents a category to explore.
Hero section accents
Add a striking band under a minimal hero, using flex-grow transitions so the row always fills the available width.
Case study and product lines
Showcase projects beside a team card or expand collections near a product card, with a gradient keeping captions readable.
Related: Paper.js Vector Blob
See the Paper.js Vector Blob for a related animations pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

All panels share the row through flex-grow, so raising one panel's grow value automatically squeezes the others within the same flexible space. Transitioning flex-grow lets the whole row rebalance in one smooth motion, and because no pixel widths are set, the gallery stays fully responsive to its container.

Each caption starts at opacity 0 and nudged down with translateY. When the panel gains the is-open class, the caption transitions in with a short delay, so it appears just after the panel begins widening. That stagger makes the label feel part of the expansion rather than popping in abruptly.

Yes. Panels expand on mouseenter for pointers and also on click, so a tap opens a panel on touchscreens where hover does not exist. Binding both events is the simplest reliable way to make the hover behaviour usable on mobile and desktop alike.

The open function toggles a single is-open class so exactly one panel carries it. All sizing, the caption reveal, and the overlay are driven by CSS from that one class, which keeps the JavaScript trivial and the animation entirely declarative.

Keep the open index in state and render panels from an array, applying the is-open class where the index matches. Bind onMouseEnter and onClick to set the index. All the animation is CSS, so nothing else changes; in Tailwind use grow utilities with arbitrary flex-grow values and a transition on flex-grow.