Loom Loader
Threads drawn through a frame and pulled off the far side, with a shuttle crossing them.
Installation
npx shadcn@latest add @loomui/loom-loaderUsage
import { LoomLoader } from "@/components/ui/loom-loader"<LoomLoader />A spinner says only that something is happening. This one says the same thing in the shape of the work. Warp threads drawn down the frame one after another, and a shuttle carrying the weft across them.
The threads are drawn and pulled off rather than faded in and out. A thread that fades is a thread that never went anywhere, and the loop stops reading as progress within about two cycles of watching it.
Size and colour
<LoomLoader className="text-accent size-16" />The loader is sized entirely by className, and it draws in currentColor, so
it inherits the colour of whatever it sits in. Put it inside a button and it is
the button's label colour without being told.
Threads carry pathLength="1", which means the dash animation is written in
fractions of a line rather than in pixels. The same keyframes hold at size-4
and at size-24, and nothing has to measure the SVG at runtime.
Threads and pace
<LoomLoader strands={7} duration={2000} />strands is how many warp threads are on the frame. Three reads as a small
inline indicator. Seven fills a page-level one. Past about nine the threads are
closer together than the stroke is wide and the frame turns into a block.
duration is one thread's whole trip, drawn and pulled off, and it also sets
the shuttle's crossing. Each thread starts a fraction behind the one before it. That is what makes five
lines read as a weave instead of five lines blinking together.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
strands | number | 5 | Warp threads on the frame. |
duration | number | 1400 | Milliseconds for one thread's trip. |
label | string | "Loading" | Announced while the loader is on screen. |
className | string | none | Merged onto the root. Size and colour go here. |
Any other <div> prop is forwarded.
Accessibility
The root is a role="status" with an accessible name, so a screen reader is
told the page is busy without the SVG being described stroke by stroke. Under
prefers-reduced-motion the threads hold fully drawn. A woven glyph rather
than an empty frame, because a loader that renders as nothing is worse than
one that does not move.