Web InnoventixFreeCode

Quote Overlay Effect

Original · free

A pull-quote overlays the image with a gradient scrim.

byWeb InnoventixReact + Tailwind
quoteoverlayimageeffect
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-quote-overlay.json
imgfx-quote-overlay.tsx
"use client";

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

export default function ImgfxQuoteOverlay() {
  const prefersReduced = useReducedMotion();
  const figureRef = useRef<HTMLDivElement>(null);
  const inView = useInView(figureRef, { once: true, margin: "-15% 0px" });

  const reveal = (delay: number) =>
    prefersReduced
      ? { initial: { opacity: 1 }, animate: { opacity: 1 } }
      : {
          initial: { opacity: 0, y: 26 },
          animate: inView ? { opacity: 1, y: 0 } : { opacity: 0, y: 26 },
          transition: {
            duration: 0.7,
            delay,
            ease: [0.22, 1, 0.36, 1] as [number, number, number, number],
          },
        };

  return (
    <section className="relative w-full overflow-hidden bg-neutral-50 px-5 py-20 sm:px-8 sm:py-28 dark:bg-neutral-950">
      <style>{`
        @keyframes iqvo_sheen {
          0%   { transform: translateX(-120%) skewX(-12deg); opacity: 0; }
          22%  { opacity: 0.55; }
          60%  { opacity: 0; }
          100% { transform: translateX(240%) skewX(-12deg); opacity: 0; }
        }
        @keyframes iqvo_rule {
          0%   { transform: scaleY(0); }
          100% { transform: scaleY(1); }
        }
        .iqvo_sheen {
          animation: iqvo_sheen 6.5s cubic-bezier(0.4, 0, 0.2, 1) 1.1s infinite;
        }
        .iqvo_rule {
          transform-origin: top;
          animation: iqvo_rule 0.9s cubic-bezier(0.22, 1, 0.36, 1) 0.5s both;
        }
        @media (prefers-reduced-motion: reduce) {
          .iqvo_sheen { animation: none; opacity: 0; }
          .iqvo_rule { animation: none; transform: scaleY(1); }
        }
      `}</style>

      <div className="mx-auto max-w-4xl">
        <div className="mb-8 flex items-center gap-3">
          <span className="h-px w-8 bg-rose-400 dark:bg-rose-500" />
          <p className="text-xs font-semibold uppercase tracking-[0.28em] text-rose-600 dark:text-rose-400">
            Quote Overlay
          </p>
        </div>

        <motion.figure ref={figureRef} {...reveal(0)} className="group relative">
          <div className="relative overflow-hidden rounded-2xl shadow-2xl shadow-neutral-900/20 ring-1 ring-neutral-900/10 dark:shadow-black/60 dark:ring-white/10">
            {/* eslint-disable-next-line @next/next/no-img-element */}
            <img
              src="/img/gallery/g14.webp"
              alt="Portrait of a founder standing at a sunlit studio window, mid-thought"
              loading="lazy"
              draggable={false}
              className="aspect-[4/5] w-full object-cover transition-transform duration-[1200ms] ease-out will-change-transform group-hover:scale-[1.04] sm:aspect-[16/10]"
            />

            {/* gradient scrim */}
            <div
              aria-hidden="true"
              className="absolute inset-0 bg-gradient-to-t from-neutral-950/90 via-neutral-950/45 to-transparent"
            />
            <div
              aria-hidden="true"
              className="absolute inset-0 bg-gradient-to-br from-rose-950/25 via-transparent to-indigo-950/25 mix-blend-multiply"
            />

            {/* sheen sweep */}
            <div
              aria-hidden="true"
              className="pointer-events-none absolute inset-0 overflow-hidden"
            >
              <div className="iqvo_sheen absolute inset-y-0 -left-1/3 w-1/3 bg-gradient-to-r from-transparent via-white/40 to-transparent" />
            </div>

            {/* pull-quote */}
            <figcaption className="absolute inset-x-0 bottom-0 flex items-end gap-4 p-6 sm:gap-5 sm:p-10">
              <span
                aria-hidden="true"
                className="iqvo_rule mt-1 hidden w-[3px] shrink-0 self-stretch rounded-full bg-gradient-to-b from-rose-400 to-indigo-400 sm:block"
              />
              <blockquote className="max-w-2xl">
                <p className="text-2xl font-semibold leading-snug tracking-tight text-white sm:text-4xl sm:leading-[1.15]">
                  <span aria-hidden="true" className="text-rose-400">
                    &ldquo;
                  </span>
                  We stopped chasing pixel-perfect and started shipping. The site
                  paid for itself in a single quarter.
                  <span aria-hidden="true" className="text-indigo-400">
                    &rdquo;
                  </span>
                </p>
                <cite className="mt-4 block text-sm not-italic text-neutral-300">
                  <span className="font-semibold text-white">Priya Nair</span>
                  <span className="mx-2 text-neutral-500">/</span>
                  Founder, Meridian Studio
                </cite>
              </blockquote>
            </figcaption>
          </div>
        </motion.figure>

        <motion.p
          {...reveal(0.15)}
          className="mt-5 text-center text-sm text-neutral-500 dark:text-neutral-400"
        >
          Hover the image &mdash; a light sheen sweeps across while the quote holds
          on a soft gradient scrim.
        </motion.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 →