Hover Zoom Gallery
A free media component for an image gallery hover effect in React, with a slow zoom and contrast-safe caption reveal.
Customise
Code
<MediaHoverZoom items={items} />Hover Zoom Gallery is a free image gallery hover effect for Next.js and React, styled with Tailwind and driven entirely by CSS. It reserves every tile's aspect ratio, then eases the image closer while a caption rises over a fully settled gradient scrim.
Linked tiles give keyboard focus the same zoom, caption and visible ring as pointer hover. Non-linked figures, touch devices and no-hover devices keep every caption visible without interaction, while reduced motion removes all scale and translation.
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/media-hover-zoomUsage
import { MediaHoverZoom } from "@/components/media-hover-zoom";
export function Example() {
return (
<MediaHoverZoom
items={[
{
id: "cliff-house",
src: "/cliff-house.jpg",
alt: "Concrete house set into a coastal cliff",
caption: "Cliff House, Madeira",
href: "/projects/cliff-house",
},
{
id: "courtyard",
src: "/courtyard.jpg",
alt: "Sunlit stone courtyard planted with olive trees",
caption: "Olive Courtyard, Puglia",
},
{
id: "lake-studio",
src: "/lake-studio.jpg",
alt: "Timber studio reflected in a still mountain lake",
caption: "Lake Studio, Cumbria",
},
]}
columns={3}
aspectRatio={4 / 3}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| items | { id: string; src: string; alt: string; caption: string; href?: string }[] | required | Three to nine images in display order. The stable id preserves tile identity when the array is reordered. |
| columns | 2 | 3 | 3 | Number of columns used from the medium breakpoint upwards. |
| aspectRatio | number | 4 / 3 | Positive width divided by height ratio reserved for every tile to prevent layout shift. |
| className | string | undefined | Additional classes merged onto the gallery grid. |
Customisation
Set columns and aspectRatio to reshape the gallery without changing its content. Two Tier 3 tokens control the caption band: --media-hover-zoom-scrim is the ink the gradient fades in over the image, and --media-hover-zoom-caption is the caption colour that sits on it. Both are theme-stable by default, because a photograph does not invert when the page does, and together they hold the caption above 4.5:1 over any image. Override them in a matched pair, so the caption keeps a backdrop it is readable on. --primary and --primary-foreground are exactly that pair, and both exist in a plain shadcn install:
<MediaHoverZoom
items={projects}
columns={2}
aspectRatio={16 / 10}
className="[--media-hover-zoom-scrim:var(--primary)] [--media-hover-zoom-caption:var(--primary-foreground)]"
/>Frequently asked questions
- Is Hover Zoom Gallery free for commercial use?
- Yes. Hover Zoom Gallery is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Is the image gallery hover effect accessible?
- Yes. Linked tiles are single anchors named by their captions, preserve meaningful image alt text and show the same treatment for keyboard focus as pointer hover. Figures remain non-interactive with visible figcaptions, and touch or reduced-motion users never need hover to discover content.
- How do I customise the gallery layout and caption backing?
- Choose two or three columns, pass a positive aspectRatio for the tile shape, and override --media-hover-zoom-scrim and --media-hover-zoom-caption as a pair to retint the caption band. Point them at tokens your app defines, such as --primary and --primary-foreground, so the override still resolves in a plain shadcn install. The component uses semantic border and ring colours throughout, and the caption band keeps both of its inks theme-stable so the image reads the same on a light page as on a dark one.