Skeleton
<Skeleton> is a single rounded rectangle with a subtle shimmer. Compose several of them to mimic the layout that’s about to render — never to fill empty space.
When to use
- The first paint of a list, card, or detail page that’s fetching its data.
- Anywhere the user expects content to appear in a known shape within ~1 second.
Don’t use Skeleton for: long fetches (≥ 3s should show progress, not pulse), zero-results (use EmptyState), or for purely decorative placeholders that never get replaced.
Single shape
<Skeleton className="h-4 w-3/5" /><Skeleton className="h-4 w-4/5" /><Skeleton className="h-4 w-2/5" />Card placeholder
Mimic the shape of the card that’s coming, not a generic gray block.
<div className="rounded-md border p-4"> <div className="flex items-center gap-3"> <Skeleton className="size-10 rounded-full" /> <div className="space-y-2"> <Skeleton className="h-4 w-32" /> <Skeleton className="h-3 w-20" /> </div> </div> <div className="mt-4 space-y-2"> <Skeleton className="h-3 w-full" /> <Skeleton className="h-3 w-5/6" /> </div></div>API
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Width, height, border-radius — every visible attribute. Required in practice. |
...rest | HTMLAttributes<HTMLDivElement> | — | Forwarded native attributes. |
Design guidelines
✓ Do
- Match the skeleton to the real content layout — a 4-line description gets 4 line skeletons.
- Pulse stays during the first paint only. Replace with real content as soon as the fetch resolves.
- Use rounded-full for circular avatars, default for everything else.
✗ Don't
- Use Skeleton for fetches longer than 3 seconds. That's a Loader / Progress moment.
- Animate skeletons across page transitions. They are paint-and-replace, not a permanent state.
- Stack 12 identical bars. Pick a representative shape and render 3–5 instances of it.
Accessibility
aria-hiddenis implied via the structure — the skeleton is decorative; the real content carries the meaning.- For long-running fetches that genuinely need an announcement, wrap the region in
aria-busy="true"and switch toaria-busy="false"on completion.
Related
Loader— Indeterminate spinner overlay for blocking operations.Progress— Determinate progress bar.EmptyState— When the fetch resolves to zero rows.