Skeleton line

One placeholder bar with a shimmer — the atom every loading layout is built from. React packages/ui/src/components/Skeleton.tsx (SkLine), CSS apps/web/src/ds/skeleton.css (.sk.sk-line).

The rule it exists for: a loading screen has the same metrics as the loaded one, so nothing jumps when the data arrives. A spinner where a list will be is a layout shift waiting to happen.

When to use

  • Any slot whose content you can approximate: a name, a value, a heading, a paragraph line.
  • Together with .sk-circle from the same sheet, to rebuild the shape of the thing that is coming (.sk-sq/.sk-box/.sk-pill were unused and removed as dead code in acrm !4058, 28 Sep 2026).

When not to use

  • A wait with no layout of its own (a button, a dialog action) — that is loader.
  • A long listing loading or paging — that is list-loader.
  • A load that failed — that is error-state.
  • A load that succeeded and returned nothing — that is empty-state.

Anatomy

  • span.sk.sk-line with an optional width (w), plus sm or lg.
  • Heights, measured: sm 8px · default 11px · lg 13px.
  • Shimmer: animation: sk-sweep 1.4s from skeleton.css — the component sets no animation of its own.
  • Width is the only thing the call site passes; everything else comes from the sheet.

Best practices

Do

  • Vary the widths. Real text is ragged, and a column of identical bars reads as a table rather than as text.
  • Match the size to the type it stands in for: sm for meta lines, default for body, lg for headings and record names.
  • Keep the same number of rows the first screenful will actually have.
  • Use 100% inside a grid cell or a flex row so the placeholder tracks the real layout.

Don't

  • Set a height inline — the sheet owns it, and an inline height is what the DS ratchet blocks.
  • Animate anything yourself.
  • Show skeletons for longer than the data takes; if the wait is genuinely long, the listing footer takes list-loader.
  • Fill a whole page with them when only one panel is loading.

Content

None — a skeleton has no words. Anything the user needs to read while waiting belongs next to it, not inside it.

  • skeleton-list — the ready-made row skeleton built from these lines.
  • loader, list-loader — waits without a layout to hold.
  • Stories: components--skeleton-line--default, --variants, --sizes, --states, --composition.

Source: docs/loading/skeleton-line.usage.md · GitLab