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.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<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.jsonOr, 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
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Put HoverExpandGalleryItem children here |
activeIndex | number | null | — | Controlled expanded index; null means every panel collapses to an equal share |
defaultActiveIndex | number | null | 0 | Initial 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 |
expandOnHover | boolean | true | Whether to expand on cursor hover |
expandedFlex | number | 5 | flex-grow weight of the expanded panel |
collapsedFlex | number | 1 | flex-grow weight of a collapsed panel |
gap | number | 8 | Gap between panels (px) |
minItemSize | number | 44 | Minimum size of a collapsed panel (px) |
aria-label | string | "InteractionGallery" | Accessible name for the gallery group (the English source includes this default — pass this prop to name it in your own language) |
HoverExpandGalleryItem
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Full-bleed background visual for the panel (image, gradient, and so on) |
label | ReactNode | — | Title revealed on expand, which also serves as the accessible name |
description | ReactNode | — | Subtitle revealed on expand |
icon | ReactNode | — | 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
activeIndexis out of range or set tonull, every panel is laid out atcollapsedFlexin 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>carryingaria-expandedto reflect its expanded state, withlabel(ordescription) as its accessible name. - The container is
role="group"with anaria-label, overridable through the prop of the same name. - Keyboard:
Tabmoves focus panel by panel, arrow keys (←/→ when horizontal, ↑/↓ when vertical) move focus between panels,Home/Endjump to the first and last;Enter/Spacecommits the expansion. - When the user has "reduce motion" enabled at the system level, panel sizes and reveals switch instantly with no transition animation.
Tilt Card
A 3D perspective tilt card — the card tilts with the cursor, a glare sweeps across its surface, it springs back on leave, and content can float up with translateZ.
Bento Grid
A bento-box grid layout — cards reveal with a stagger, and on hover the focused card lifts while the rest dim slightly.