Skip to content

Feedback

Skeleton

The shape of the page, before the page.

When to reach for it

A wait the reader would otherwise think was a broken page. A shape that describes what is coming beats a dot that describes nothing.

Examples

record list

Loading projects

parts

Loading the example

Notes

The fill every skeleton part is drawn from: --stone, and nothing else.

Deliberately NOT a shimmer. A shimmer sweeps a highlight across the shape, which implies a light source; the White Reset has none, so the sweep reads as a bug rather than as loading. The whole page breathes together instead — see SkeletonPage, which owns the single pulse.

Props

Also accepts everything in HTMLAttributes<HTMLDivElement>. Those are forwarded to the underlying element and are not listed row by row.

Parts

Composed at the call site rather than configured through props, so a layout this component did not anticipate is still expressible.

SkeletonLine

A line of type. Height is the line's; width is how far it runs.

Also accepts everything in HTMLAttributes<HTMLDivElement>. Those are forwarded to the underlying element and are not listed row by row.

SkeletonBlock

A block: an image mount, a plate, a chart.

Also accepts everything in HTMLAttributes<HTMLDivElement>. Those are forwarded to the underlying element and are not listed row by row.

SkeletonCircle

A circle: an avatar, a marker.

Also accepts everything in HTMLAttributes<HTMLDivElement>. Those are forwarded to the underlying element and are not listed row by row.

SkeletonText

A paragraph.

The last line is short, because real prose ends mid-measure. A block of equal full-width bars reads as a table, and the reader then flinches when a paragraph arrives instead.

SkeletonText props
PropTypeDefaultDescription
linesnumber3How many lines of prose to stand in for.

Also accepts everything in HTMLAttributes<HTMLDivElement>. Those are forwarded to the underlying element and are not listed row by row.

SkeletonPage

The frame a skeleton sits in: the live region, and the single pulse.

One animate-pulse on the wrapper rather than one per part, so the page breathes together instead of shimmering out of phase — twenty independently animated bars is a visual noise floor, not a loading state.

A skeleton whose shape does not match what replaces it is worse than none: it promises a layout and then the page jumps out from under the reader. Compose the parts to match the real thing, and change both together.

SkeletonPage props
PropTypeDefaultDescription
childrenrequiredReactNode
labelrequiredstringWhat is loading, in words. Announced once; the shapes themselves are `aria-hidden`, so this sentence is the entire experience for a screen reader and "Loading" alone tells it nothing.

Also accepts everything in HTMLAttributes<HTMLDivElement>. Those are forwarded to the underlying element and are not listed row by row.

Accessibility

  • One live region on the wrapper; every shape inside it is aria-hidden.
  • One pulse on the wrapper, not one per bar, so the page breathes together.