Skeleton

A content-shaped placeholder for content whose layout is already known — it says what is about to appear and where. That is the whole difference from a Spinner, which says only that you are waiting, and from Progress, which says how much of a known total is done. Reach for a skeleton only when the shape is genuinely known: one that guesses wrong is a layout shift with extra steps.

Skeleton · Loading a card

An avatar, two heading lines, a media area, and a paragraph — the shape of the content that is coming, not a decorative arrangement. Each bar carries a --ds-skeleton-delay one step further on, so the group reads as a wave rather than one flashing slab. The frame is a presentation-only outline, not a Card: a demo of one component should not put another under test. The region carries one aria-busy and every bar is aria-hidden, so a screen reader hears it once rather than six times, and every width is the host's.

Shapes

Each shape sets the one dimension a host cannot infer from its own layout, and nothing else. Width is always the host's, because only the host knows how wide the content it stands in for will be. So is the pulse's offset: --ds-skeleton-delay staggers a group into a wave, and unlike a shimmer sweep it needs no shared coordinate space.

ExampleShapeModifierSetsUsage
Text--textfont.size.copy-md heightA line of copy — the default, and the overwhelming case
Block--blocksize.control.lg floor, radius.controlMedia, a chart, a card body; the floor only keeps it visible when a host forgets a height
Circle--circlesize.control.md boxAn Avatar — its large box, since a placeholder avatar carries a whole row on its own

Which waiting signal

The three divide by what the system actually knows. Picking by appearance rather than by knowledge is how a spinner ends up standing in for a known layout, or a skeleton for a request that may never return.

ExampleComponentKnowsSaysUsage
SpinnerNothingWaitDuration and shape both unknown
ProgressA totalThis much is doneMeasurable work — uploads, imports, batches
SkeletonThe shapeThis is coming, hereA known layout waiting on its data

Usage notes

A skeleton is a promise about layout. Breaking it costs more than the spinner it replaced.

VerdictRule
DoMark the loading region aria-busy="true" and every skeleton aria-hidden="true" — the region announces once, the bars never do.
DoMatch the skeleton to the content it replaces, not to a pleasing arrangement. Three bars where two lines will land is a promise the interface then breaks.
Don’tUse a skeleton when you are guessing at the shape — that is a Spinner, which promises nothing about layout and so cannot break the promise.
Don’tLeave a skeleton standing for something that may never arrive. A failed load is an EmptyState or an error; a skeleton pulsing forever is a hang with a nice texture.
Don’tAnimate a shimmer across a group at layer 1. Coordinating a sweep needs the skeletons to share a coordinate space, which is layout, which is layer 2.