Skeleton
Holds the shape of content while it loads.
Shape
blockdefault
text
rows
Usage
When to use it
- Use
- A region waits on its first load and its shape is known: a list of rows, a data list, a header.
- Not for
- A task with a count. Use Progress.
- Not for
- A button waiting on its own action. Use Button.
- Not for
- The load failed or returned nothing. Use Empty state.
Rules
6 rules
- Never
- Animate a skeleton: no pulse, no sweep. Because Sodium has one loop, the pending mark, and a moving block is a second one that says nothing the block does not.
- Must
- Show a skeleton through SkeletonSwap, not a bare loading ternary. Because SkeletonSwap waits 150ms before it shows and holds 400ms once shown, so a fast load never flashes.
- Never
- Swap content already on screen back to a skeleton on a refresh. Because the person loses their place in what they were reading; SkeletonSwap keeps the content and marks it busy.
- Must
- Pass SkeletonText the type role of the text it stands in for. Because each line is one line box of that role, so the heights match and nothing moves when the text lands.
- Never
- Round a skeleton, even one for an avatar. Because every corner in Sodium is square, the avatar included.
- Should
- Give SkeletonRows the page size, so the frame keeps its height when the rows land.
Accessibility
2 checks
- Every skeleton is aria-hidden; SkeletonSwap holds a status region that says the label once it shows.
- The region is aria-busy while loading and while refreshing.
Edge cases
4 edge cases
- Load under 150ms
- The skeleton never shows; its space is held, so nothing moves.
- Load at 170ms
- The skeleton shows for 400ms, so it does not blink.
- Refresh
- The content stays and the region is aria-busy.
- Forced colours
- Blocks draw in GrayText.
API
5 props
Skeleton classNamestringSkeletonText type, lines, lastTextRole, number, numberdefault'body', 1, 0.6SkeletonRows rowsnumberdefault4SkeletonSwap loading, fallback, labelboolean, ReactNode, stringSkeletonSwap delay, minDurationnumberdefault150, 400
Tokens
4 tokens
--well- #f4f3ee
--row- 40px
--line-faint- #efede6
--marker- 8px