Skeleton

Skeletons are small placeholder blocks that can be used while content is still loading.

Examples

Basic usage

<div class="flow">
            <div class="skeleton" style="inline-size: 12rem"></div>
            <div class="skeleton" style="inline-size: 9rem"></div>
        </div>

Circle

<div class="cluster">
            <div class="skeleton is-circle"></div>
            <div class="skeleton is-circle" style="--skeleton-size: 3.5rem"></div>
            <div class="skeleton is-circle" style="--skeleton-size: 5rem"></div>
        </div>

Animated

<div class="skeleton-shimmer flow">
            <div class="skeleton" style="inline-size: 14rem; block-size: 1rem"></div>
            <div class="skeleton" style="inline-size: 11rem; block-size: 1rem"></div>
            <div class="skeleton" style="inline-size: 8rem; block-size: 1rem"></div>
        </div>

Multi-line text

<div class="skeleton-shimmer stack is-tight">
            <div class="skeleton" style="inline-size: 95%; block-size: 0.875rem"></div>
            <div class="skeleton" style="inline-size: 88%; block-size: 0.875rem"></div>
            <div class="skeleton" style="inline-size: 60%; block-size: 0.875rem"></div>
        </div>

List item

<div class="skeleton-shimmer stack">
            <div class="media">
                <div class="skeleton is-circle media-figure"></div>
                <div class="media-body stack is-tight">
                    <div class="skeleton" style="inline-size: 40%; block-size: 0.875rem"></div>
                    <div class="skeleton" style="inline-size: 70%; block-size: 0.75rem"></div>
                </div>
            </div>
            <div class="media">
                <div class="skeleton is-circle media-figure"></div>
                <div class="media-body stack is-tight">
                    <div class="skeleton" style="inline-size: 55%; block-size: 0.875rem"></div>
                    <div class="skeleton" style="inline-size: 60%; block-size: 0.75rem"></div>
                </div>
            </div>
            <div class="media">
                <div class="skeleton is-circle media-figure"></div>
                <div class="media-body stack is-tight">
                    <div class="skeleton" style="inline-size: 35%; block-size: 0.875rem"></div>
                    <div class="skeleton" style="inline-size: 80%; block-size: 0.75rem"></div>
                </div>
            </div>
        </div>

Card

<div class="card skeleton-shimmer" aria-busy="true" aria-label="Loading">
                <div
                    class="skeleton"
                    style="block-size: 8rem; border-radius: var(--radius-md) var(--radius-md) 0 0"
                ></div>
                <div class="stack" style="padding: var(--space-md)">
                    <div class="skeleton" style="inline-size: 60%; block-size: 1.25rem"></div>
                    <div class="stack is-tight">
                        <div class="skeleton" style="inline-size: 90%; block-size: 0.875rem"></div>
                        <div class="skeleton" style="inline-size: 70%; block-size: 0.875rem"></div>
                    </div>
                    <div class="cluster">
                        <div class="skeleton is-circle" style="--skeleton-size: 1.75rem"></div>
                        <div class="skeleton" style="inline-size: 5rem; block-size: 0.75rem"></div>
                    </div>
                </div>
            </div>

Table rows

Name Role Status Joined
<div class="table-wrap">
            <table class="table">
                <thead>
                    <tr>
                        <th>Name</th>
                        <th>Role</th>
                        <th>Status</th>
                        <th>Joined</th>
                    </tr>
                </thead>
                <tbody class="skeleton-shimmer" aria-busy="true">
                    <tr>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 80%; block-size: 0.75rem"
                            ></div>
                        </td>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 60%; block-size: 0.75rem"
                            ></div>
                        </td>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 50%; block-size: 0.75rem"
                            ></div>
                        </td>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 70%; block-size: 0.75rem"
                            ></div>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 65%; block-size: 0.75rem"
                            ></div>
                        </td>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 75%; block-size: 0.75rem"
                            ></div>
                        </td>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 40%; block-size: 0.75rem"
                            ></div>
                        </td>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 55%; block-size: 0.75rem"
                            ></div>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 90%; block-size: 0.75rem"
                            ></div>
                        </td>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 50%; block-size: 0.75rem"
                            ></div>
                        </td>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 65%; block-size: 0.75rem"
                            ></div>
                        </td>
                        <td>
                            <div
                                class="skeleton"
                                style="inline-size: 45%; block-size: 0.75rem"
                            ></div>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>

Source comments

Skeleton -- placeholder block for content that's still loading.

Multi-line text placeholders compose stacked .skeleton bars in a
.flow or .stack. No .is-text variant is shipped: a single tall
block sized for N lines doesn't actually look like multi-line
text, so consumers stack bars explicitly.

Markup:
  <div class="skeleton" style="inline-size: 12rem; block-size: 1rem"></div>
  <div class="skeleton is-circle"></div>
  <div class="skeleton is-circle" style="--skeleton-size: 3.5rem"></div>

  <div class="skeleton-shimmer flow">
      <div class="skeleton" style="inline-size: 75%; block-size: 1rem"></div>
      <div class="skeleton" style="inline-size: 60%; block-size: 1rem"></div>
  </div>

Archetype: Atom (P3). Pure CSS, no JS.

Mode asymmetry: the fill scale flips intensity direction by mode.
In light mode the shimmer band is lighter than the base (bright
sweep). In dark mode it's darker than the base (dark sweep).
Both register as motion; the visual character differs slightly.
The base + highlight pair sits one step apart on the fill scale
in either direction, deliberately tame -- skeletons are
affordance, not theater.

Reduced motion: the keyframes themselves are overridden to a no-op
inside @media (prefers-reduced-motion: reduce). The gradient stays
visible (the static striped look reads as "loading" too); only the
animation pauses.

Accessibility: skeletons are decorative -- they convey "loading"
visually but carry no semantic value. Add aria-hidden="true" on
each skeleton, or wrap the loading region in [aria-busy="true"]
so assistive tech announces the loading state and skips the
placeholders.

Reference

Source: src/css/extras/skeleton.css

Applies to

.skeleton

Classes

ClassKindDescription
.is-circlevariantCircle placeholder for avatar or icon stand-ins

Tokens

TokenDefaultDescription
--skeleton-colorvar(--color-fill-strong)Base fill tint for the skeleton block
--skeleton-highlightvar(--color-fill)Shimmer band tint for the animated sweep
--skeleton-radiusvar(--radius-sm)Corner radius for the skeleton block
--skeleton-size2.5remDiameter of the circle placeholder