Web InnoventixFreeCode

Zoom Desaturate Effect

Original · free

Image zooms and desaturates with a title on hover.

byWeb InnoventixReact + Tailwind
zoomdesaturateimageeffect
Open

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/imgfx-zoom-desaturate.json
imgfx-zoom-desaturate.tsx
"use client";

const IZD_TILES = [
  {
    src: "/img/gallery/g07.webp",
    alt: "Fog drifting between tall evergreen trees at dawn",
    eyebrow: "Field notes",
    title: "Quiet Timberline",
  },
  {
    src: "/img/gallery/g19.webp",
    alt: "Sunlit dunes rippling across a wide desert basin",
    eyebrow: "Field notes",
    title: "Slow Dunes",
  },
  {
    src: "/img/gallery/g23.webp",
    alt: "Weathered coastal cliffs meeting a calm grey sea",
    eyebrow: "Field notes",
    title: "Edge of Tide",
  },
];

export default function ImgfxZoomDesaturate() {
  return (
    <section className="relative w-full bg-white px-6 py-20 sm:px-10 sm:py-28 dark:bg-neutral-950">
      <style>{`
        @keyframes izd-fade {
          from { opacity: 0; transform: translateY(12px); }
          to   { opacity: 1; transform: translateY(0); }
        }
        .izd-fade { animation: izd-fade 0.7s cubic-bezier(0.22, 1, 0.36, 1) both; }
        .izd-img {
          transition: transform 0.8s cubic-bezier(0.22, 1, 0.36, 1),
                      filter 0.6s ease;
        }
        .izd-card:hover .izd-img,
        .izd-card:focus-within .izd-img {
          transform: scale(1.12);
          filter: grayscale(1) contrast(1.06);
        }
        .izd-veil {
          transition: opacity 0.6s ease;
        }
        .izd-card:hover .izd-veil,
        .izd-card:focus-within .izd-veil { opacity: 1; }
        .izd-caption {
          transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1),
                      opacity 0.5s ease;
        }
        .izd-card:hover .izd-caption,
        .izd-card:focus-within .izd-caption {
          transform: translateY(0);
          opacity: 1;
        }
        @media (prefers-reduced-motion: reduce) {
          .izd-fade { animation: none; }
          .izd-img, .izd-veil, .izd-caption { transition: none; }
        }
      `}</style>

      <div className="mx-auto max-w-6xl">
        <div className="izd-fade mb-12 text-center sm:mb-16">
          <p className="mb-3 text-xs font-semibold uppercase tracking-[0.25em] text-indigo-600 dark:text-indigo-400">
            Zoom &amp; Desaturate
          </p>
          <h2 className="text-3xl font-semibold tracking-tight text-neutral-900 sm:text-4xl dark:text-neutral-50">
            The frame leans in and the color slips away
          </h2>
          <p className="mx-auto mt-4 max-w-xl text-sm text-neutral-500 dark:text-neutral-400">
            Hover any photo to push in close and drain it to monochrome while the title rises into view.
          </p>
        </div>

        <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
          {IZD_TILES.map((tile, i) => (
            <figure
              key={tile.src}
              tabIndex={0}
              className="izd-card group izd-fade relative aspect-[4/5] overflow-hidden rounded-2xl bg-neutral-200 shadow-sm outline-none ring-1 ring-neutral-900/5 transition-shadow duration-500 hover:shadow-2xl focus-visible:ring-2 focus-visible:ring-indigo-500 dark:bg-neutral-800 dark:ring-white/10"
              style={{ animationDelay: `${0.15 + i * 0.12}s` }}
            >
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img
                src={tile.src}
                alt={tile.alt}
                loading="lazy"
                draggable={false}
                className="izd-img absolute inset-0 h-full w-full object-cover"
              />

              <div className="izd-veil pointer-events-none absolute inset-0 bg-gradient-to-t from-neutral-950/85 via-neutral-950/25 to-transparent opacity-70" />

              <figcaption className="izd-caption absolute inset-x-0 bottom-0 translate-y-3 p-5 opacity-0">
                <p className="mb-1 text-[0.7rem] font-medium uppercase tracking-[0.2em] text-indigo-300">
                  {tile.eyebrow}
                </p>
                <h3 className="text-xl font-semibold text-white drop-shadow-sm">
                  {tile.title}
                </h3>
                <span className="mt-2 inline-flex h-px w-10 bg-indigo-400" aria-hidden="true" />
              </figcaption>
            </figure>
          ))}
        </div>

        <p className="izd-fade mt-8 text-center text-xs uppercase tracking-[0.2em] text-neutral-400 dark:text-neutral-600">
          Hover or focus to reveal
        </p>
      </div>
    </section>
  );
}

Dependencies

None (React + Tailwind only).

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 quote

Similar components

Browse all →