Skeleton screen

Grey placeholder shapes in the layout of the content that is loading, so a page looks like it is filling in rather than frozen.

the pulsing grey boxes before stuff loadsloading ghostskeleton loaderskelaton screenshimmer placeholdergrey placeholder blocks while loadingcontent placeholderghost UI

See it

Live demo coming soon

What it is

A skeleton screen replaces loading content with grey blocks shaped like the thing that is coming: a circle where the avatar goes, two bars where the name and subtitle go. Facebook popularised it, and the usual finish is a soft pulse or a shimmer sweeping left to right so the page reads as working rather than stuck.

Use it when the layout is predictable and the wait is roughly 300ms to a few seconds. Below that, show nothing: a flash of skeleton is worse than a beat of stillness. Above that, hand over to a progress indicator: a determinate bar with a percentage if you can genuinely measure the work (bytes uploaded, rows imported), and an indeterminate spinner with useful status text ('Importing 1,200 rows') when you cannot. A made-up percentage that crawls to 90 and parks there is worse than no number at all. Skeletons buy perceived speed, not actual speed.

Gotcha: a skeleton whose boxes do not match the final layout makes things worse, because the content lands and everything jumps. Match the dimensions. And never let a skeleton stand in for an error or an empty list, or people sit watching a placeholder pulse forever waiting for data that is never coming.

Ask AI for it

Build a skeleton loading state for this card list: for each item render grey placeholder blocks matching the real layout (a 40px circle for the avatar, a 60% width bar for the title, two full-width bars for the body, 8px rounded corners). Use a surface color one step off the background, animate a shimmer gradient sweeping left to right on a 1.5s loop, and fall back to a static block under prefers-reduced-motion. Keep every skeleton box the exact size of the loaded content so nothing shifts on swap, and only show it after a 300ms delay so fast responses never flash it.

You might have meant

empty stateprogress barcardindeterminate progress indicator