Skeleton
Also called shimmer, content placeholder, ghost loader, skeleton screen
A low-contrast shape that occupies the same space as the content still loading, so the layout is visible before the data arrives.
Example
Loading state
Loading posts
Toggle between the two states — the rows keep the same height, so nothing on the page moves when the content arrives.
When to use it
- The layout is known in advance — a list of cards, a table, a profile header.
- Loading usually takes somewhere between 300ms and a couple of seconds.
- Several pieces of content arrive independently and you want the page to settle progressively rather than all at once.
- You want to avoid layout shift: the skeleton reserves the exact space the content will take.
When not to
- Loads that finish under ~300ms. The skeleton flashes and reads as a glitch — render nothing instead.
- You don't know the shape of what's coming. A skeleton that doesn't match the final layout causes the shift it was meant to prevent.
- Waiting on an action the user just triggered, like submitting a form. A button spinner keeps the feedback attached to the thing they clicked.
- Long or open-ended waits. After a few seconds a skeleton stops reassuring and starts looking broken — switch to a progress indicator with an explanation.
Trade-offs
- Makes waiting feel shorter by showing structure immediately.
- Reserves layout space, so content does not jump when it arrives.
- Communicates roughly how much is coming before it gets there.
- Has to be kept in sync with the real layout, or it becomes a second design to maintain.
- Reads as broken on long waits because it carries no progress information.
- Animated shimmer can be distracting and needs a reduced-motion fallback.
Accessibility
What this pattern needs in order to work for everyone.
- Keyboard
- Skeletons are not focusable — they are decorative stand-ins, not controls.
- Focus must not be trapped in the loading region; keep the surrounding page usable.
- Roles and state
- Wrap the loading region in `role="status"` so assistive tech announces it politely.
- Set `aria-busy="true"` on the container while loading, and remove it when content arrives.
- Hide the skeleton shapes themselves with `aria-hidden`; announce a short text like “Loading posts” instead.
- Focus
- If focus was inside the region before loading started, move it to a stable ancestor rather than letting it fall to the body.
In the wild
- YouTube — Video grid renders card-shaped skeletons that match thumbnail and title dimensions exactly.
- LinkedIn — Popularised the pattern for feeds, where post height is roughly predictable.
Compared with
Side-by-side breakdowns of patterns that solve a similar problem.