Cards & Grids

Hover Expand Gallery

A horizontally squeezing expand gallery — panels change their share of the space on hover or keyboard focus, while the rest collapse and dim.

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add hover-expand-gallery.en

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

5
1
8
Active edited usageDefault props
<HoverExpandGallery/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add https://webberui.com/r/hover-expand-gallery.en.json

Or, once registries are configured in components.json, install it as @webberui/hover-expand-gallery.

Usage

import {
  HoverExpandGallery,
  HoverExpandGalleryItem,
} from "@/components/ui/hover-expand-gallery";

<HoverExpandGallery className="h-64 w-full max-w-md" defaultActiveIndex={0}>
  <HoverExpandGalleryItem label="Ridge" description="The ridgeline at daybreak">
    <img src="/mountain.jpg" alt="" className="h-full w-full object-cover" />
  </HoverExpandGalleryItem>
  <HoverExpandGalleryItem label="Bay" description="Sandbars after the tide goes out">
    <img src="/bay.jpg" alt="" className="h-full w-full object-cover" />
  </HoverExpandGalleryItem>
</HoverExpandGallery>;

Each panel's share of the space is driven by its flex-grow weight: the expanded panel grows while the rest collapse proportionally. The container needs a height (horizontal orientation) or a width (vertical), and the panels fill it automatically.

Props

HoverExpandGallery

PropTypeDefaultDescription
childrenReactNode—Put HoverExpandGalleryItem children here
activeIndexnumber | null—Controlled expanded index; null means every panel collapses to an equal share
defaultActiveIndexnumber | null0Initial expanded index in uncontrolled mode; set null for equal shares by default
onActiveIndexChange(index: number | null) => void—Fires when the expanded index is committed (hover does not fire it)
orientation"horizontal" | "vertical""horizontal"Layout direction: horizontal or vertical squeeze
expandOnHoverbooleantrueWhether to expand on cursor hover
expandedFlexnumber5flex-grow weight of the expanded panel
collapsedFlexnumber1flex-grow weight of a collapsed panel
gapnumber8Gap between panels (px)
minItemSizenumber44Minimum size of a collapsed panel (px)
aria-labelstring"InteractionGallery"Accessible name for the gallery group (the English source includes this default — pass this prop to name it in your own language)

HoverExpandGalleryItem

PropTypeDefaultDescription
childrenReactNode—Full-bleed background visual for the panel (image, gradient, and so on)
labelReactNode—Title revealed on expand, which also serves as the accessible name
descriptionReactNode—Subtitle revealed on expand
iconReactNode—Corner identifier icon that stays visible when collapsed

How it works

  • The expanded state is decided by two layers, "hovered" and "committed (active)": hovering temporarily expands the hovered panel, and leaving returns to the active panel.
  • Clicking or keyboard-focusing a panel commits it as active, so when browsing with the keyboard the focused panel is the expanded one.
  • When activeIndex is out of range or set to null, every panel is laid out at collapsedFlex in equal shares.
  • An expanded panel reveals a gradient mask and title along its bottom edge, while collapsed panels get a translucent dark layer to sharpen the focus.

Accessibility

  • Each panel is a native <button> carrying aria-expanded to reflect its expanded state, with label (or description) as its accessible name.
  • The container is role="group" with an aria-label, overridable through the prop of the same name.
  • Keyboard: Tab moves focus panel by panel, arrow keys (←/→ when horizontal, ↑/↓ when vertical) move focus between panels, Home / End jump to the first and last; Enter / Space commits the expansion.
  • When the user has "reduce motion" enabled at the system level, panel sizes and reveals switch instantly with no transition animation.