Web InnoventixFreeCode

Rounded Hover Effect

Original · free

A rounded image that lifts with a soft shadow on hover.

byWeb InnoventixReact + Tailwind
roundedhoverimageeffect
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-rounded-hover.json
imgfx-rounded-hover.tsx
"use client";

import { useRef } from "react";
import { motion, useInView, useReducedMotion } from "motion/react";

const PHOTOS = [
  { src: "/img/gallery/g07.webp", alt: "Sunlit studio workspace with a laptop and warm morning light" },
  { src: "/img/gallery/g18.webp", alt: "Quiet coastal path curving toward the sea at golden hour" },
  { src: "/img/gallery/g24.webp", alt: "Overhead view of a ceramic coffee cup on a linen table" },
];

export default function ImgfxRoundedHover() {
  const reduce = useReducedMotion();
  const ref = useRef<HTMLDivElement>(null);
  const inView = useInView(ref, { once: true, margin: "-80px" });

  return (
    <section className="relative w-full overflow-hidden bg-neutral-50 px-6 py-20 sm:py-28 dark:bg-neutral-950">
      <style>{`
        .rhfx-card {
          transition:
            transform 420ms cubic-bezier(0.16, 1, 0.3, 1),
            box-shadow 420ms cubic-bezier(0.16, 1, 0.3, 1);
          will-change: transform;
        }
        .rhfx-card:hover,
        .rhfx-card:focus-visible {
          transform: translateY(-14px);
          box-shadow:
            0 2px 6px rgba(15, 23, 42, 0.06),
            0 24px 48px -12px rgba(15, 23, 42, 0.28);
        }
        .rhfx-card:focus-visible {
          outline: 2px solid rgb(99 102 241);
          outline-offset: 6px;
        }
        .rhfx-img {
          transition: transform 620ms cubic-bezier(0.16, 1, 0.3, 1);
        }
        .rhfx-card:hover .rhfx-img,
        .rhfx-card:focus-visible .rhfx-img {
          transform: scale(1.06);
        }
        :is(.dark) .rhfx-card:hover,
        :is(.dark) .rhfx-card:focus-visible {
          box-shadow:
            0 2px 6px rgba(0, 0, 0, 0.5),
            0 28px 56px -12px rgba(0, 0, 0, 0.65);
        }
        @media (prefers-reduced-motion: reduce) {
          .rhfx-card,
          .rhfx-img { transition: none; }
          .rhfx-card:hover,
          .rhfx-card:focus-visible { transform: none; }
          .rhfx-card:hover .rhfx-img,
          .rhfx-card:focus-visible .rhfx-img { transform: none; }
        }
      `}</style>

      <div className="mx-auto max-w-6xl">
        <div className="mb-12 max-w-2xl">
          <p className="text-xs font-semibold uppercase tracking-[0.2em] text-indigo-600 dark:text-indigo-400">
            Image Effect
          </p>
          <h2 className="mt-3 text-3xl font-semibold tracking-tight text-neutral-900 sm:text-4xl dark:text-neutral-50">
            Rounded Lift
          </h2>
          <p className="mt-3 text-base text-neutral-600 dark:text-neutral-400">
            Hover any photo and it floats up with a soft, believable shadow.
          </p>
        </div>

        <div ref={ref} className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
          {PHOTOS.map((photo, i) => (
            <motion.div
              key={photo.src}
              initial={reduce ? false : { opacity: 0, y: 28 }}
              animate={inView || reduce ? { opacity: 1, y: 0 } : undefined}
              transition={{ duration: 0.6, delay: reduce ? 0 : i * 0.1, ease: [0.16, 1, 0.3, 1] }}
            >
              <a
                href={photo.src}
                target="_blank"
                rel="noopener"
                className="rhfx-card group block overflow-hidden rounded-3xl bg-white ring-1 ring-neutral-200/70 dark:bg-neutral-900 dark:ring-white/10"
                aria-label={`Open photo: ${photo.alt}`}
              >
                <div className="aspect-[4/5] overflow-hidden rounded-3xl">
                  {/* eslint-disable-next-line @next/next/no-img-element */}
                  <img
                    src={photo.src}
                    alt={photo.alt}
                    loading="lazy"
                    draggable={false}
                    className="rhfx-img h-full w-full object-cover"
                  />
                </div>
              </a>
            </motion.div>
          ))}
        </div>

        <p className="mt-8 text-sm text-neutral-500 dark:text-neutral-500">
          Tip: keyboard-focus a photo to see the same lift.
        </p>
      </div>
    </section>
  );
}

Dependencies

motion

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 →