Skeleton Atom

Shapes for the free-form case, and a matching .Skeleton on every Composition. The second half is the point: a placeholder built from the same tokens as the real thing cannot drift out of sync with it, so the page does not jump when data lands.

Shapes

tsx · motion on
<Skeleton width="12rem" height="1rem" /><Skeleton.Text lines={3} /><Skeleton.Circle size="3rem" />

Composition skeletons

tsx · motion on
{loading ? <Statistic.Skeleton withVisual /> : <Statistic {...stat} />}

Do

Reach for the Composition's own .Skeleton, so the placeholder keeps the real layout's size.

Don't

Hand-assemble grey boxes that approximate the card — they will be wrong the first time the card changes.

Props

PropTypeDefaultNotes
width / heightstring'100%' / '1rem'Any CSS length. Prefer rem so it scales with type.
radius'sm' | 'md' | 'lg' | 'full''md'Corner token.
Skeleton.Text linesnumber3Line count; the last line is short, as real text is.
Skeleton.Text lastLineWidthstring'62%'Width of that last line.
Skeleton.Circle sizestring'2.5rem'Diameter — for avatars and rings.

Accessibility and motion

Every shape is aria-hidden, so a screen reader hears the loading state from your live region rather than from a wall of empty boxes. The shimmer is CSS and stops under prefers-reduced-motion — the shapes stay, which is what communicates "loading".