v1.2.0

Skeleton

A loading placeholder shaped like the content it stands in for.

Shapes

A line of text, an avatar and a card or an image. The pulse runs while the data loads.

html
<div class="vt-skeleton vt-skeleton-line" aria-hidden="true"></div>
<div class="vt-skeleton vt-skeleton-circle" aria-hidden="true"></div>
<div class="vt-skeleton vt-skeleton-card" aria-hidden="true"></div>

Text

Several lines stand in for a paragraph; the last one is shorter, as the last line of text usually is.

html
<div class="vt-flex vt-flex-col vt-gap-2" aria-hidden="true">
  <div class="vt-skeleton vt-skeleton-line"></div>
  <div class="vt-skeleton vt-skeleton-line"></div>
  <div class="vt-skeleton vt-skeleton-line"></div>
</div>

List Row

An avatar and two lines — the shape of a list item or a comment.

html
<div class="vt-flex vt-items-center vt-gap-3" aria-hidden="true">
  <div class="vt-skeleton vt-skeleton-circle"></div>
  <div class="vt-flex vt-flex-col vt-gap-2 vt-flex-1">
    <div class="vt-skeleton vt-skeleton-line"></div>
    <div class="vt-skeleton vt-skeleton-line"></div>
  </div>
</div>
<div class="vt-flex vt-items-center vt-gap-3" aria-hidden="true">
  <div class="vt-skeleton vt-skeleton-circle"></div>
  <div class="vt-flex vt-flex-col vt-gap-2 vt-flex-1">
    <div class="vt-skeleton vt-skeleton-line"></div>
    <div class="vt-skeleton vt-skeleton-line"></div>
  </div>
</div>

Card

A card that is loading keeps its frame; the placeholders fill its body.

html
Loading…
<div class="vt-card vt-w-full vt-max-w-sm" aria-busy="true">
  <div class="vt-card-body">
    <div class="vt-skeleton vt-skeleton-card" aria-hidden="true"></div>
    <div class="vt-flex vt-flex-col vt-gap-2" aria-hidden="true">
      <div class="vt-skeleton vt-skeleton-line"></div>
      <div class="vt-skeleton vt-skeleton-line"></div>
    </div>
    <span class="vt-sr-only">Loading…</span>
  </div>
</div>

Block

A bare vt-skeleton takes whatever size the layout gives it — a button, a chart, a tab.

html
<div class="vt-skeleton vt-w-32 vt-h-8" aria-hidden="true"></div>
<div class="vt-skeleton vt-w-24 vt-h-8" aria-hidden="true"></div>

Guidelines

Do
Shape the placeholders like the content that is coming, so the page does not jump when it arrives.
Don't
Don't use a skeleton for an action in progress — a button that saves shows a spinner.

Anatomy

div[aria-busy="true"]              ← The region that is loading
├── div.vt-skeleton.vt-skeleton-*   ← One placeholder per piece of content (aria-hidden)
└── span.vt-sr-only                 ← "Loading…" for screen readers

API Reference

Class Type Description
vt-skeleton Base The placeholder surface — surface-moderate, radius-md, a slow pulse; a bare block takes the size the layout gives it
vt-skeleton-line Shape A line of text — full width, 16px tall, radius-2xs; the last of several lines is 60% wide
vt-skeleton-circle Shape An avatar — 40px, round
vt-skeleton-card Shape A card or an image — full width, 96px tall, radius-2xl

Accessibility

Feature Details
Busy The region that is loading carries aria-busy="true" until the content arrives
Hidden The placeholders are decoration: aria-hidden="true", with one visually hidden "Loading…" for screen readers
Motion The pulse stops under prefers-reduced-motion; the placeholders stay visible