Logo Loom

A logo row woven into place, every other mark arriving from the other side of the thread.

Loading preview

Installation

npx shadcn@latest add @loomui/logo-loom

Usage

import { LogoLoom } from "@/components/ui/logo-loom"
<LogoLoom>
  <NorthwindLogo />
  <ContosoLogo />
  <FabrikamLogo />
</LogoLoom>

Hand it a flat list of marks. It lays them out, runs a thread through the row, and weaves them in when the row scrolls into view.

Why it reads as woven

One thread runs behind the whole row. Every other logo carries a background, which hides the thread where it crosses. The rest are transparent, so the thread runs straight through them. That alternation is the interlacing (over, under, over) rather than a row of logos sitting on a line.

The pass a logo takes is also the direction it arrives from, so the row laces itself together as it lands instead of dropping in from one side.

<LogoLoom stagger={90} duration={700} distance="1.6rem" />

stagger is the delay between one logo arriving and the next, duration the length of a single arrival, and distance how far each one travels.

One keyframe covers both passes. The direction lives in a --loom-from custom property, set per logo, so there is no second animation to keep in step with the first.

When it runs

<LogoLoom repeat />

By default the row weaves once, the first time it comes into view. repeat resets it whenever the row leaves, so it weaves again on the way back.

thread={false} drops the line and keeps the arrival.

Under prefers-reduced-motion the logos are shown in place with no travel.

Props

PropTypeDefaultDescription
staggernumber90Milliseconds between one logo arriving and the next.
durationnumber700Length of a single arrival.
distancestring"1.6rem"How far a logo travels in.
threadbooleantrueDraw the thread the logos are woven onto.
repeatbooleanfalseWeave again every time the row returns to view.
classNamestringnoneMerged onto the row. Gaps go here.

Any other <div> prop is forwarded.

Accessibility

The thread is aria-hidden. The logos are your own markup, so give an img an alt and an inline svg a title. Nothing here supplies a name for them. Reduced motion shows the row rather than leaving it waiting on a scroll.