Web InnoventixFreeCode

Outline Draw Effect

Original · free

An SVG outline strokes around the image on hover.

byWeb InnoventixReact + Tailwind
outlinedrawimageeffect
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-outline-draw.json
imgfx-outline-draw.tsx
"use client";

import { useId } from "react";

export default function ImgfxOutlineDraw() {
  const gradId = useId().replace(/:/g, "");

  return (
    <section className="relative w-full bg-neutral-50 px-6 py-20 dark:bg-neutral-950 sm:px-10 sm:py-28">
      <style>{`
        .odraw-outline-${gradId} {
          stroke-dasharray: 100;
          stroke-dashoffset: 100;
          opacity: 0;
          transition:
            stroke-dashoffset 0.9s cubic-bezier(0.65, 0, 0.35, 1),
            opacity 0.25s ease;
        }
        .odraw-card-${gradId}:hover .odraw-outline-${gradId},
        .odraw-card-${gradId}:focus-within .odraw-outline-${gradId} {
          stroke-dashoffset: 0;
          opacity: 1;
        }
        .odraw-corner-${gradId} {
          opacity: 0;
          transform: scale(0.6);
          transform-origin: center;
          transition: opacity 0.4s ease 0.5s, transform 0.4s ease 0.5s;
        }
        .odraw-card-${gradId}:hover .odraw-corner-${gradId},
        .odraw-card-${gradId}:focus-within .odraw-corner-${gradId} {
          opacity: 1;
          transform: scale(1);
        }
        .odraw-img-${gradId} {
          transition: transform 0.9s cubic-bezier(0.65, 0, 0.35, 1), filter 0.6s ease;
        }
        .odraw-card-${gradId}:hover .odraw-img-${gradId},
        .odraw-card-${gradId}:focus-within .odraw-img-${gradId} {
          transform: scale(1.04);
          filter: saturate(1.08);
        }
        @media (prefers-reduced-motion: reduce) {
          .odraw-outline-${gradId} {
            transition: opacity 0.2s ease;
            stroke-dashoffset: 0;
          }
          .odraw-corner-${gradId} {
            transition: opacity 0.2s ease;
            transform: none;
          }
          .odraw-img-${gradId} {
            transition: none;
          }
          .odraw-card-${gradId}:hover .odraw-img-${gradId},
          .odraw-card-${gradId}:focus-within .odraw-img-${gradId} {
            transform: none;
          }
        }
      `}</style>

      <div className="mx-auto max-w-2xl text-center">
        <p className="text-xs font-semibold uppercase tracking-[0.25em] text-indigo-600 dark:text-indigo-400">
          Outline Draw
        </p>
        <h2 className="mt-3 text-3xl font-semibold tracking-tight text-neutral-900 dark:text-neutral-50 sm:text-4xl">
          A line traces the frame on hover
        </h2>
        <p className="mt-3 text-sm text-neutral-500 dark:text-neutral-400">
          Hover the photo and a crisp stroke draws itself around the edge, corner accents snapping in last.
        </p>
      </div>

      <div className="mx-auto mt-14 max-w-lg">
        <figure
          tabIndex={0}
          className={`odraw-card-${gradId} group relative block overflow-visible rounded-2xl outline-none`}
        >
          <div className="relative overflow-hidden rounded-2xl">
            {/* eslint-disable-next-line @next/next/no-img-element */}
            <img
              src="/img/gallery/g14.webp"
              alt="Sunlight breaking across a mountain ridge at dawn"
              loading="lazy"
              draggable={false}
              className={`odraw-img-${gradId} block h-auto w-full select-none`}
            />
          </div>

          <svg
            className="pointer-events-none absolute inset-0 h-full w-full"
            viewBox="0 0 100 100"
            preserveAspectRatio="none"
            aria-hidden="true"
          >
            <defs>
              <linearGradient id={`stroke-${gradId}`} x1="0" y1="0" x2="1" y2="1">
                <stop offset="0%" stopColor="#818cf8" />
                <stop offset="50%" stopColor="#a78bfa" />
                <stop offset="100%" stopColor="#6366f1" />
              </linearGradient>
            </defs>
            <rect
              className={`odraw-outline-${gradId}`}
              x="1.2"
              y="1.2"
              width="97.6"
              height="97.6"
              rx="7"
              ry="7"
              pathLength={100}
              fill="none"
              stroke={`url(#stroke-${gradId})`}
              strokeWidth="0.9"
              vectorEffect="non-scaling-stroke"
              strokeLinecap="round"
              strokeLinejoin="round"
            />
          </svg>

          <span
            className={`odraw-corner-${gradId} pointer-events-none absolute -left-1.5 -top-1.5 h-3 w-3 rounded-full bg-indigo-500 shadow-[0_0_12px_2px_rgba(99,102,241,0.6)]`}
            aria-hidden="true"
          />
          <span
            className={`odraw-corner-${gradId} pointer-events-none absolute -bottom-1.5 -right-1.5 h-3 w-3 rounded-full bg-violet-500 shadow-[0_0_12px_2px_rgba(139,92,246,0.6)]`}
            aria-hidden="true"
          />

          <figcaption className="mt-4 text-center text-xs font-medium uppercase tracking-widest text-neutral-400 dark:text-neutral-500">
            Ridgeline, first light
          </figcaption>
        </figure>
      </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 →