Components
SVG Draw
Wrap any inline SVG and it draws itself in, line by line, then fills.
Wrap any inline SVG, an icon, a logo or a whole illustration, and it draws itself in. Every path, line, circle, rect and polygon traces its outline one after another, then its fill fades in behind the line. Outline icons draw in their own stroke and keep it; filled shapes are traced in a thin line that fades away as they fill. It plays when the SVG scrolls into view, or on mount. GSAP DrawSVG and ScrollTrigger.
Installation
pnpm dlx shadcn@latest add @tween-ui/svg-drawUsing an AI editor? Set up MCP once, then just ask for it in plain words.
Usage
import SvgDraw from '@/components/tweenui/svg-draw';
export default function HeroMark() {
return (
<SvgDraw className="text-teal-700">
<svg
viewBox="0 0 24 24"
className="size-24"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
>
<path d="M12 3l2.6 5.6 6.1.7-4.5 4.2 1.2 6L12 16.6 6.6 19.5l1.2-6-4.5-4.2 6.1-.7z" />
</svg>
</SvgDraw>
);
}It works with whatever SVG you put inside: an icon from a library, a logo
pasted from a design tool, or a whole illustration. Tune the pace with
duration, stagger and ease, and change the key to play it again.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
duration | number | 1.4 | Seconds each shape takes to draw. |
delay | number | 0 | Seconds before the first shape starts. |
stagger | number | 0.12 | Seconds between one shape starting and the next. |
ease | string | 'power2.inOut' | Any GSAP ease. |
width | number | 1.5 | Trace width in screen px for fill-only shapes. |
trigger | 'view' | 'mount' | 'view' | Play on scrolling into view, or straight away. |
start | string | 'top 85%' | ScrollTrigger start, with trigger="view". |
onComplete | () => void | — | Called once every shape is drawn and filled. |
The trace line takes the wrapper's text color, so set it with a text-*
class. It renders a <div> around your SVG and extends native <div>
attributes (className, style, …).
Behavior
- Any shape, any SVG. It finds every
path,line,polyline,polygon,circle,ellipseandrect, however deeply nested in groups or across several SVGs. Shapes insidedefs,clipPath,mask,pattern,markerandsymbolare skipped, because they are never painted where they sit. - Strokes stay strokes, fills stay fills. A stroked shape draws in its own stroke color and width and keeps them. A fill-only shape draws in a thin line in the text color that fades out as its fill fades in. Every fill ends in its own color and opacity, gradients included.
- The same line on any scale. The trace uses a non-scaling stroke, so
widthlooks the same on a 24-unit icon and on a 1000-unit logo. - Measured by DrawSVG. Path lengths,
pathLengthattributes and line caps are all handled by GSAP's DrawSVG plugin. - Cleans up after itself. The timeline runs inside
useGSAP, so unmounting or changing a prop reverts every shape to how it was written. - No flash. Where scripts run, the SVG is hidden until its first frame is set up, before paint. Without JavaScript it simply shows.
- Only inline SVG. An
<img src="logo.svg">or a CSS background cannot be traced: paste the markup in, or import it as a component (SVGR). Shapes drawn through<use>and<text>are left as they are.
Accessibility
The drawing is decoration on top of your SVG: its markup, titles and labels
are untouched, so give the SVG an aria-label or aria-hidden as you
normally would. Under prefers-reduced-motion: reduce nothing animates and
the SVG shows as written straight away.