Web InnoventixFreeCode

Sharp Blur Effect

Original · free

Sharp image blurs with a caption appearing on hover.

byWeb InnoventixReact + Tailwind
sharpblurimageeffect
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-sharp-blur.json
imgfx-sharp-blur.tsx
"use client";

export default function ImgfxSharpBlur() {
  const cards = [
    {
      src: "/img/gallery/g07.webp",
      alt: "Sunlight cutting across a quiet mountain ridge at dawn",
      caption: "Ridgeline at first light",
      meta: "Dolomites, 05:42",
    },
    {
      src: "/img/gallery/g18.webp",
      alt: "Still water reflecting a pale morning sky",
      caption: "The lake held its breath",
      meta: "Long exposure, f/16",
    },
    {
      src: "/img/gallery/g29.webp",
      alt: "Warm street lamps glowing along an empty evening avenue",
      caption: "Last light on the avenue",
      meta: "Golden hour, 35mm",
    },
  ];

  return (
    <section className="relative w-full bg-neutral-50 px-6 py-20 dark:bg-neutral-950 sm:py-28">
      <style>{`
        .sharpblur-fx-card img {
          transition: filter 520ms cubic-bezier(0.16, 1, 0.3, 1),
                      transform 620ms cubic-bezier(0.16, 1, 0.3, 1);
          will-change: filter, transform;
        }
        .sharpblur-fx-card:hover img,
        .sharpblur-fx-card:focus-within img {
          filter: blur(9px) brightness(0.62) saturate(1.05);
          transform: scale(1.06);
        }
        .sharpblur-fx-caption {
          transition: opacity 460ms cubic-bezier(0.16, 1, 0.3, 1),
                      transform 460ms cubic-bezier(0.16, 1, 0.3, 1);
          transform: translateY(14px);
          opacity: 0;
        }
        .sharpblur-fx-card:hover .sharpblur-fx-caption,
        .sharpblur-fx-card:focus-within .sharpblur-fx-caption {
          opacity: 1;
          transform: translateY(0);
        }
        .sharpblur-fx-rule {
          transition: width 560ms cubic-bezier(0.16, 1, 0.3, 1) 60ms;
          width: 0;
        }
        .sharpblur-fx-card:hover .sharpblur-fx-rule,
        .sharpblur-fx-card:focus-within .sharpblur-fx-rule {
          width: 2.75rem;
        }
        @media (prefers-reduced-motion: reduce) {
          .sharpblur-fx-card img,
          .sharpblur-fx-caption,
          .sharpblur-fx-rule {
            transition: none;
          }
        }
      `}</style>

      <div className="mx-auto max-w-6xl">
        <div className="mb-12 text-center">
          <p className="text-xs font-semibold uppercase tracking-[0.22em] text-indigo-600 dark:text-indigo-400">
            Image Effect / Sharp Blur
          </p>
          <h2 className="mt-3 text-3xl font-semibold tracking-tight text-neutral-900 dark:text-neutral-50 sm:text-4xl">
            Crisp until you look closer
          </h2>
          <p className="mx-auto mt-4 max-w-xl text-sm leading-relaxed text-neutral-500 dark:text-neutral-400">
            Each photo stays razor-sharp at rest. Hover, and it eases into a soft
            blur while the caption rises to meet you.
          </p>
        </div>

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

              <figcaption className="sharpblur-fx-caption absolute inset-x-0 bottom-0 p-6">
                <div className="sharpblur-fx-rule mb-3 h-px bg-white/70" />
                <p className="text-lg font-semibold leading-snug text-white drop-shadow-sm">
                  {card.caption}
                </p>
                <p className="mt-1 text-xs font-medium uppercase tracking-[0.16em] text-white/70">
                  {card.meta}
                </p>
              </figcaption>

              <span className="pointer-events-none absolute right-4 top-4 rounded-full bg-white/85 px-2.5 py-1 text-[0.65rem] font-semibold uppercase tracking-wider text-neutral-800 opacity-100 backdrop-blur-sm transition-opacity duration-300 group-hover:opacity-0 group-focus-within:opacity-0 dark:bg-neutral-900/80 dark:text-neutral-100">
                {String(i + 1).padStart(2, "0")}
              </span>
            </figure>
          ))}
        </div>

        <p className="mt-8 text-center text-xs font-medium uppercase tracking-[0.18em] text-neutral-400 dark:text-neutral-500">
          Hover or focus a photo to reveal its caption
        </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 →