Skeleton
Reserves the shape of what is coming, so the page does not jump when it arrives.
Overview
A skeleton holds structure. It is worth having because layout shift under a moving finger is how the wrong row gets opened — and it is dangerous for exactly one reason, which is the rule below.
It ships with Pending value, because the rule sends you there. The two were one item and one page; a dependency does that job without documenting two components in one place.
Which of the waiting components to reach for is decided on Progress.
Skeletons
A skeleton reserves the shape of what is coming so the page does not jump when it arrives. That is worth having — layout shift under a moving finger is how the wrong row gets opened.
A skeleton may reserve structure. It may never stand where a clinical value will land. A grey bar in the place of a number is a promise that a number is coming, and the system cannot keep that promise — if the source is unreachable the bar either sits there indefinitely or vanishes leaving an empty cell, and both are indistinguishable from there is no value.
The first two rows are structure — a title and a line of text whose absence costs nothing. The third is where a measurement goes, so it is named in words with a start time rather than drawn as a shape. When it resolves it becomes a value or a stated absence, per Key–value pair, and never a blank.
- Skeletons do not animate. A shimmer performs activity, and movement is the alarm channel — a screen of pulsing placeholders spends the signal a real alarm needs. See Motion.
- A skeleton matches the real layout. If three rows are drawn and eight arrive, the page jumps anyway and the skeleton bought nothing.
- A skeleton is not a count. Drawing five placeholder rows says five results are coming. Draw a fixed structural frame, or say how many are expected if that is known.
- A skeleton has the same bound as any other wait. It resolves or it is replaced by a stated failure. A skeleton that never resolves is the quietest possible error.
What the component enforces, and what it only asks for
One rule, held by an absence in the type.
| Rule | Held by | How |
|---|---|---|
| A grey bar never stands where a number goes | The component | variant offers structural shapes only. There is no value variant, so the misuse is not expressible — and the rule points at Pending value, which installs with this.Asserted: Skeleton: structural only — there is no value variant to pass |
| It does not animate | The component | No shimmer. A skeleton that pulses performs activity that is not happening. Asserted: Skeleton: does not animate |
| It is hidden from assistive technology | The component | aria-hidden, with the surrounding region marked busy.Asserted: Skeleton: hidden from assistive technology |
| It reserves the right height | You | You choose the variant and the count. A skeleton shorter than the content it stands for still shifts the page when the content arrives. |
| It is replaced by something | You | A skeleton left rendering because a request failed is a page that never resolves. |
A rule stated on a component page reads as a rule the component keeps. 3 of these 5 are; 2 are obligations this page was quietly handing to the reader. The dangerous misuse is unexpressible. The ordinary one — leaving it there — is not.
Do's and don'ts
Structure held as shapes, the measurement named in words. When it resolves it becomes a value or a stated absence — never a blank.
A grey bar where the troponin goes. It promises a number the system may not be able to deliver, and if the assay feed is down it either sits there or disappears — both read as there is no result.
static — no shimmer
Structure held still. A skeleton that does not move reserves space without performing an activity that is not happening.
shimmering
The shimmer says something is happening. Movement is the alarm channel in this system, and a decorative pulse competes with the one movement that matters.
Three rows, because three are coming. The page arrives in the shape it will keep.
… then twelve rows load
One placeholder for twelve rows. The content arrives eleven rows taller than the space reserved for it, and a finger already descending lands on the row that moved.
Accessibility
- It is
aria-hiddenand the region carriesaria-busy="true". A screen reader announcing a row of grey bars is reading furniture. - It does not animate. A shimmer performs activity that is not happening, and movement is the alarm channel.
- It reserves the real height, so nothing moves when content replaces it — the whole reason to use one.
Outcomes of use
- Effectiveness — the page arrives in the shape it will keep, so a press lands where it was aimed.
- Efficiency — no reflow to re-read after content loads.
- Satisfaction — a page that does not flinch. Attributes believed to contribute to an outcome; the outcome is settled by observing real use, not by this page — see Usability & context of use.
Clinical safety notes
Trace these in your risk file (ISO 14971) and usability engineering file (IEC 62366-1). Which of these the component keeps and which are yours is stated in the guarantees table; a control the component does not keep is one your risk file must show you keep.
- Never stands where a clinical value will land. (the component) Mitigates: an unreachable source rendering as a bar that never resolves, or an empty cell that reads as “there is no value”. Use Pending value for that slot.
- No layout shift when content arrives. (you) Mitigates: a press landing on the row that moved into place.
Implementation
$ npx shadcn@latest add https://md.notjustany.tech/r/skeleton.json
<Skeleton variant="heading" />
// There is no "value" variant, so a grey bar cannot be put where a
// number goes. This installs pending-value with it, because that rule
// sends the reader there and an instruction pointing at something not
// installed is not an instruction.
Related
- Pending value — the slot a skeleton may not fill.
- Activity — when there is no shape to reserve.
- Motion — why none of this shimmers.