Stitch Path
A running stitch sewn along an SVG path as the page scrolls, following the holes it is laid over.
Installation
npx shadcn@latest add @loomui/stitch-pathUsage
import { StitchPath } from "@/components/ui/stitch-path"<div className="h-32">
<StitchPath />
</div>It fills its parent and stretches to whatever shape that parent is, so give it
a height. Colour comes from currentColor, so text-primary on the component
or anywhere above it is enough.
How it is sewn
The visible path carries a dash pattern, because that is what makes it read as stitches rather than a line. A dashed path cannot be wiped with its own dash offset, because both want the same property. So the reveal is a second copy of the path, stroked solid and wiped, used as a mask.
pathLength="1" normalises the path, so the offset is simply the fraction left
to sew and no geometry is ever measured.
<StitchPath stitch={5} gap={4} thickness={2} />stitch and gap set the pattern. thickness is in pixels and does not
stretch with the box, so a wide seam stays as fine as a narrow one.
guide draws the holes the thread runs through: zero-length dashes with a
round cap, one per stitch. Turn it off for bare thread.
What drives it
By default it follows its own box through the viewport. Nothing when its top edge sits on the bottom of the screen, fully sewn once its bottom edge clears the top.
<StitchPath target={sectionRef} />Pass target to follow a different element, a whole section usually, so a
short seam is paced by the copy beside it rather than by its own height.
<StitchPath progress={0.4} />Pass progress to drive it yourself, and the scroll listener is never
attached.
Your own path
<StitchPath d="M 0 50 L 100 50" viewBox="0 0 100 100" />Path data is in a 0 0 100 100 box. Because the box stretches, a straight line
stays straight and a curve keeps its shape only in proportion. Draw the shape
you want at the aspect ratio you plan to use.
Under prefers-reduced-motion the seam is drawn complete and no listener runs.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
d | string | an S-bend | Path data, in the 0 0 100 100 box. |
stitch | number | 5 | Length of one stitch. |
gap | number | 4 | Bare thread between two stitches. |
thickness | number | 2 | Thread thickness in pixels. |
progress | number | none | Sew it yourself, 0 to 1. |
target | RefObject | own box | Element to follow through the viewport. |
guide | boolean | true | Draw the holes the thread is sewn through. |
className | string | none | Merged onto the svg. Colour goes here. |
Any other <svg> prop is forwarded.
Accessibility
The whole svg is aria-hidden. It is decoration, and a seam has nothing a
reader would want announced. Reduced motion draws it complete rather than
leaving it half sewn.