Skip to content

Skeleton

A Skeleton is a set of generic placeholder shapes that reserve a page’s layout while its real content is on its way. It renders as plain HTML and CSS with no JavaScript, so it can paint before an app hydrates — softening the jump from an empty page to a populated one.

Quarantine

The skeleton is a small set of generic shapes — a line, a block, and a circle — that stand in for content while it loads. They are intentionally abstract: a skeleton hints at the shape of what’s coming without mimicking it pixel for pixel. Keep placeholders simpler than the real layout; a rough echo reads as “loading”, an exact replica reads as broken.

  1. Block
  2. Line
  3. Circle

Use a skeleton when:

  • Content takes long enough to load that an empty page would feel broken, and you can predict the rough shape of what’s coming.
  • You want to reserve layout space so the page doesn’t jump when content arrives.
  • The placeholder can render before the app hydrates — skeletons are plain HTML/CSS and need no JavaScript.

Avoid a skeleton when:

  • The wait is very short (a sub-second flash is more distracting than nothing).
  • You can’t predict the layout, so the placeholder wouldn’t match what loads.
  • A single, small action is loading — a spinner or inline progress indicator is clearer.
  • The operation can fail and needs a message — skeletons imply success is imminent; use an error or empty state instead.

Three base shapes cover most placeholders. Compose them — with the existing layout and utility classes — to mirror the layout that will replace them.

Block

The default shape — image, media, or card placeholder. The caller sets its size, so a block can stand in for anything from a thumbnail to a hero frame.

Line

Text placeholder. Stack a few at varying widths to suggest a paragraph or heading, with the last line shorter than the rest to mimic the natural break.

Circle

Avatar or icon placeholder. Use it when the real content will be a circular image or rounded badge.

Desktop

Use skeletons to reserve the dominant blocks of the layout — hero media, card grids, sidebar sections. Match the real layout’s structure so nothing reflows when the content arrives.

Tablet

Same composition as desktop, but stack blocks more aggressively as the grid collapses. Keep the same skeleton shapes — only the layout changes.

Mobile

Drop to single-column skeletons. Keep lines short enough to suggest mobile typography without filling the whole viewport.

The skeleton can animate to reinforce that content is loading. The treatment is still being decided across three candidates, so while the component is in quarantine all three are available for evaluation:

  • Static (current default) — no motion. The cheapest and most restrained.
  • Pulse — the fill gently breathes opacity. Calm, and implies no direction.
  • Shimmer — a highlight sweeps across the fill. The most familiar pattern, but the busiest.

Whichever is chosen, motion is suppressed under prefers-reduced-motion and the skeleton falls back to a static fill.

Suggest the layout — never replicate it.

Do

Match the placeholder to the real layout’s structure (same rough number of lines, same block proportions), keep skeletons simpler than the content they replace, reserve the space the real content will occupy so the page doesn’t reflow, and use one consistent motion treatment across a view.

Don't

Don’t show a skeleton for loads short enough that it only flashes, don’t build a pixel-perfect replica of the content (abstraction is the point), don’t mix several motion treatments on the same page, and don’t use a skeleton to mask an error or empty state — those need their own messaging.

The skeleton carries no copy of its own — its job is to hint at the layout, not the words. If a region holds a critical message (“Sorry, we couldn’t load this”) it deserves an explicit error or empty state instead of a placeholder pretending success.