Cmpnts

Menu

Atoms

Skeleton

A placeholder that holds the space of content still loading, so nothing moves when it arrives.


Loading a summary…

Code
HTML
<div class="stack" aria-busy="true">
  <p class="sr-only" role="status">Loading a summary…</p>
  <span class="skeleton skeleton--text" aria-hidden="true"></span>
</div>

Why it exists

A blank space while content loads looks broken, and a page that jumps when content arrives can move what someone was about to press. A Skeleton holds the space with the shape of what’s coming, so the page already looks like itself and nothing moves.

A text line takes its height from the text atom it sits in, so the bar matches the text that replaces it. The fill mixes the text colour, so it shows the same on any surface, and it stops moving for anyone who has asked for reduced motion.

A shape tells a screen reader nothing, so it’s hidden, and the loading is said once in words. There is no loading Card or loading Table to learn, either. A loading Card is an ordinary Card with shapes inside.

When to use

  • While content whose shape you know is loading: a Card list, a profile, a Table.
  • Not for a task with a known end: that is a progress bar.
  • Not when there is nothing to show: that is an Empty State.

Rules

  • Text lines size from the text atom they sit in. Put --text and --heading inside the atom the loaded text will use.
  • Don’t hold a heading’s place with a heading. Use the atom class on a div, not on an h1–h6: a heading with only hidden content is an empty heading.

Keyboard and screen readers

All of this is the product’s markup and script. The library only draws the shapes.

  • Every shape takes aria-hidden="true".
  • The region takes aria-busy="true" and a role="status" message (“Loading activity…”), which is what a screen reader hears.
  • When loading ends, set aria-busy="false" and update or remove the message.
  • A companion control is disabled (or not focusable) as well as aria-hidden, so Tab never lands on a placeholder.

Text Lines

Code
HTML
<div class="small-heading"><span class="skeleton skeleton--heading" aria-hidden="true"></span></div>
<p class="text">
  <span class="skeleton skeleton--text" aria-hidden="true"></span>
  <span class="skeleton skeleton--text skeleton--w-75" aria-hidden="true"></span>
</p>

Reuse the Real Atom

A companion keeps the atom’s own box, so nothing shifts when the real one replaces it. The Skeleton only replaces the paint.

Code
HTML
<div class="avatar skeleton" aria-hidden="true"><span>AB</span></div>
<button type="button" class="button skeleton" aria-hidden="true" disabled><span>Submit</span></button>
<span class="status skeleton" aria-hidden="true"><span class="status__text">Active</span></span>

Loading Card

Team activity

Loading team activity…

Code
HTML
<article class="card" aria-busy="true" aria-labelledby="activity-title">
  <header class="card__header">
    <span class="skeleton skeleton--avatar" aria-hidden="true"></span>
    <hgroup class="card__hgroup">
      <h3 id="activity-title" class="card__title small-heading">Team activity</h3>
      <p class="card__subtitle small-text"><span class="skeleton skeleton--text" aria-hidden="true" style="--skeleton-width: 8rem;"></span></p>
    </hgroup>
  </header>
  <div class="card__body">
    <p class="sr-only" role="status">Loading team activity…</p>
    <span class="skeleton skeleton--media" aria-hidden="true"></span>
    <p class="text">
      <span class="skeleton skeleton--text" aria-hidden="true"></span>
      <span class="skeleton skeleton--text skeleton--w-75" aria-hidden="true"></span>
    </p>
  </div>
  <footer class="card__footer">
    <button type="button" class="button button--subtle skeleton" aria-hidden="true" disabled><span>Open</span></button>
  </footer>

</article>

Do and Don’t

DoDon’t
Match the shape of what will arrive.Show a generic block that jumps when content loads.
Announce loading once, with role="status".Leave screen reader users with silence, or a list of empty shapes.
Put aria-hidden="true" on every shape.Put a heading tag on a line with only hidden content.
Make a companion control disabled.Leave a placeholder Button in the tab order.

In Storybook

See also

  • Progress and Meter: A bar for how far a task has got, or for a measurement within a known range.
  • Card: A surface with named parts, such as a header, a body and a footer, for one thing a person can read, compare or act on.
  • Empty State: The block shown where content would be when there is none, saying why and what to do next.

Search the docs