Skeleton
Skeleton — the wait when the shape of what is coming is known: the layout appears first, in grey, and the content fills it.
Beta · Feedback and status · packages/css/src/components/skeleton.css
.pui-skeleton · shape --line --circle --block · circle sizes --24 --64 (40 default) · --on-card (automatic inside .pui-card).
Sizes across, states down.
What it is for
Section titled “What it is for”- Shape: line (radius 4 — a line of text; height is the text’s line-height), circle (radius full — an avatar), block (radius 8 — a card, an image, a chart)
- Size: three specimen sizes; in use a skeleton takes the exact size of what it stands in for, so the page does not jump when the content lands
- No properties beyond shape and size; no states; no text
Use when a region whose layout is known is loading — a table, a card grid, a profile header — and the wait is longer than a blink.
Do not use when the layout is unknown (Spinner); the region is empty for good (Empty); the wait is measurable (Progress).
Relates to Spinner, Progress, Empty, Card, Table, Avatar.
Anti-patterns a skeleton that is not the size of the content (the jump is worse than the wait) · a skeleton for a button · more than one pulse rhythm on a screen · a skeleton with a border.
Keywords: skeleton, loading, placeholder, shimmer, pulse
Figma — page Spinner, Skeleton & Progress: Skeleton (18 variants)
shadcn: skeleton
The markup — copy this
Section titled “The markup — copy this”The class, the parts, and nothing that is not in the package. The same block opens skeleton.css.
<span class="pui-skeleton pui-skeleton--line" style="width: 280px"></span><span class="pui-skeleton pui-skeleton--circle pui-skeleton--40"></span><div class="pui-skeleton pui-skeleton--block" style="height: 120px"></div>The modifiers
Section titled “The modifiers”| What it is | Note | |
|---|---|---|
| Shape | (none) line, radius 4, 1 em tall · --circle, radius full · --block, radius 8 | — |
| Size | the consumer’s — width and height of the thing it stands for; --24 / --40 / --64 for a circle | — |
| On card | --on-card, or automatically inside a tinted .pui-card (surface/slot). In a white card (--plain, --border) it is the grey of a white ground | — |
Accessibility — measured, not assumed
Section titled “Accessibility — measured, not assumed”Every number here is measured on the rendered component: contrast (npm run contrast:render), the focus ring (npm run focus) and the keyboard (npm run keyboard). The floors are principle 12’s.
Contrast
Section titled “Contrast”No story of this component renders a text pair axe can measure — a component made of surfaces and borders rather than words. The token pairs it uses are in artifacts/contrast-matrix.md.
The focus ring
Section titled “The focus ring”Nothing in this component takes focus.
Keyboard
Section titled “Keyboard”Nothing in this component claims an ARIA role with a keyboard contract; its controls are ordinary ones and the browser already gives them their keys.
Tab order across the whole library is document order over 344 stops, and Shift+Tab is its exact reverse — no keyboard trap anywhere (WCAG 2.1.2).
Pepper UI v1.5.0
The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.