Image Card Hover Effect
Original · freeAn image card with a title overlay that reveals on hover.
Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.
npx shadcn@latest add https://webinnoventix.com/r/hover-image-card.json"use client";
import { useId } from "react";
type Card = {
img: string;
eyebrow: string;
title: string;
blurb: string;
href: string;
};
const CARDS: Card[] = [
{
img: "/img/gallery/g07.webp",
eyebrow: "Field Notes",
title: "Desert Highway at Dusk",
blurb: "A 40-minute detour that turned into the best shot of the trip.",
href: "#desert-highway",
},
{
img: "/img/gallery/g19.webp",
eyebrow: "Studio",
title: "Slow Coffee, Warm Light",
blurb: "Behind the scenes of the morning still-life series.",
href: "#slow-coffee",
},
{
img: "/img/gallery/g23.webp",
eyebrow: "Travel",
title: "Above the Cloud Line",
blurb: "Six hours up, one clear window, thirty seconds of gold.",
href: "#cloud-line",
},
];
export default function HoverImageCard() {
const uid = useId();
const prefix = `hic-${uid.replace(/[^a-zA-Z0-9]/g, "")}`;
return (
<section className="relative w-full bg-slate-50 px-4 py-16 sm:px-6 sm:py-20 dark:bg-slate-950">
<style>{`
@keyframes ${prefix}-rise {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.${prefix}-card:hover .${prefix}-img,
.${prefix}-card:focus-within .${prefix}-img {
transform: scale(1.06);
}
.${prefix}-card:hover .${prefix}-veil,
.${prefix}-card:focus-within .${prefix}-veil {
opacity: 1;
}
.${prefix}-card:hover .${prefix}-reveal,
.${prefix}-card:focus-within .${prefix}-reveal {
opacity: 1;
transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
.${prefix}-img,
.${prefix}-veil,
.${prefix}-reveal {
transition: none !important;
}
.${prefix}-card:hover .${prefix}-img,
.${prefix}-card:focus-within .${prefix}-img {
transform: none;
}
}
`}</style>
<div className="mx-auto max-w-6xl">
<div className="mx-auto mb-10 max-w-2xl text-center sm:mb-14">
<h2 className="text-3xl font-semibold tracking-tight text-slate-900 sm:text-4xl dark:text-white">
Selected Work
</h2>
<p className="mt-3 text-base text-slate-600 dark:text-slate-400">
Hover or focus a card to reveal the story behind the frame.
</p>
</div>
<ul className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{CARDS.map((card, i) => (
<li key={card.href}>
<a
href={card.href}
aria-label={`${card.title} — ${card.eyebrow}`}
className={`${prefix}-card group relative block aspect-[4/5] overflow-hidden rounded-2xl bg-slate-200 shadow-sm ring-1 ring-slate-900/5 transition-shadow duration-300 hover:shadow-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 dark:bg-slate-800 dark:ring-white/10 dark:focus-visible:ring-offset-slate-950`}
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={card.img}
alt={card.title}
loading="lazy"
draggable={false}
className={`${prefix}-img absolute inset-0 h-full w-full object-cover transition-transform duration-[600ms] ease-out will-change-transform`}
/>
<div
className={`${prefix}-veil pointer-events-none absolute inset-0 bg-gradient-to-t from-slate-950/85 via-slate-950/30 to-transparent opacity-70 transition-opacity duration-300`}
aria-hidden="true"
/>
<div className="absolute inset-x-0 top-0 flex items-start justify-between p-4">
<span className="inline-flex items-center rounded-full bg-white/85 px-3 py-1 text-xs font-medium tracking-wide text-slate-800 backdrop-blur-sm dark:bg-slate-900/70 dark:text-slate-100">
{card.eyebrow}
</span>
<span
className="inline-flex h-8 w-8 items-center justify-center rounded-full bg-white/85 text-slate-800 opacity-0 transition-opacity duration-300 group-hover:opacity-100 group-focus-within:opacity-100 dark:bg-slate-900/70 dark:text-slate-100"
aria-hidden="true"
>
<svg
viewBox="0 0 20 20"
fill="none"
className="h-4 w-4"
stroke="currentColor"
strokeWidth="1.75"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M5 15 15 5" />
<path d="M7 5h8v8" />
</svg>
</span>
</div>
<div className="absolute inset-x-0 bottom-0 p-5">
<h3 className="text-lg font-semibold text-white drop-shadow-sm">
{card.title}
</h3>
<p
className={`${prefix}-reveal mt-1.5 translate-y-2 text-sm text-slate-200 opacity-0 transition-all duration-300 ease-out`}
style={{ transitionDelay: "60ms" }}
>
{card.blurb}
</p>
<span
className={`${prefix}-reveal mt-3 inline-flex items-center gap-1.5 text-sm font-medium text-indigo-300 opacity-0`}
style={{ transitionDelay: "120ms" }}
>
View story
<svg
viewBox="0 0 20 20"
fill="none"
className="h-3.5 w-3.5"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M4 10h11" />
<path d="M11 5l5 5-5 5" />
</svg>
</span>
</div>
{i === 0 && (
<span
className="absolute left-4 top-16 inline-flex items-center rounded-full bg-emerald-500/90 px-2.5 py-0.5 text-xs font-medium text-white"
style={{
animation: `${prefix}-rise 0.5s ease-out both`,
}}
>
Featured
</span>
)}
</a>
</li>
))}
</ul>
</div>
</section>
);
}Dependencies
Licence
Built by Web Innoventix. Free for personal and commercial use, no attribution required.
Built by Web Innoventix
Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.
Get a free quoteSimilar components
Browse all →
Card Lift Hover Effect
OriginalA card that lifts with a growing shadow on hover.

Card Glow Hover Effect
OriginalA card with a coloured glow that blooms on hover.

Card Border Draw Hover Effect
OriginalA card whose border draws itself in on hover.

Card Gradient Shift Hover Effect
OriginalA card whose gradient background shifts on hover.

Card Tilt Hover Effect
OriginalA card that tilts in 3D toward the cursor on hover.

Card Spotlight Hover Effect
OriginalA card with a cursor-following radial spotlight.

Link Underline Hover Effect
OriginalAnimated link underline effects: grow, slide and centre-out.

Link Slide Hover Effect
OriginalLinks whose label slides up to a duplicate on hover.

Button Fill Hover Effect
OriginalButtons with a colour fill that sweeps across on hover.

Button Shine Hover Effect
OriginalButtons with a diagonal shine sweep on hover.
Icon Fill Hover Effect
OriginalIcon buttons whose icon and background fill on hover.
Icon Bounce Hover Effect
OriginalIcons that bounce or spin playfully on hover.

