Skeleton

Holds the shape of content while it loads, so the page doesn't jump when it arrives.

Live React portVue source: WildSkeleton.vueStorybook story: Feedback/SkeletonReact component: WSkeleton

Try it

Pick a shape, then turn on Loaded to see the content it holds the place of.

Variant
Width
Height
Loaded
<WildSkeleton
  variant="text"
/>

When to use

  • Use a skeleton while a list, card or reading loads and its layout is already known.
  • Build it to the layout that replaces it, so nothing moves when the data lands.
Don’t use it
  • For an action the person just started. Use the loading state on Button.
  • For a job with a known end. Use Progress bar.
  • When the result is empty. Use Empty state.

Variants

One shape for each thing that loads: a line of text, an avatar, a square-cornered block and a card.

text
circular
rectangular
rounded
rounded · radius 16
<WildSkeleton variant="text" width="70%" />
<WildSkeleton variant="text" width="45%" />
<WildSkeleton variant="circular" />
<WildSkeleton variant="rectangular" height={72} />
<WildSkeleton variant="rounded" height={72} />
<WildSkeleton variant="rounded" height={72} radius={16} />
Rounded defaults to 8px corners. Set radius to 16 when it stands in for a dashboard widget card.

Sizes

28px
40px
56px
<WildSkeleton variant="circular" width={28} />
<WildSkeleton variant="circular" />
<WildSkeleton variant="circular" width={56} />
A circle stays a circle. Give it one dimension and the other follows.

Composition

Give each part you’re replacing a skeleton of its own shape. Use count for a run of lines.

<WildSkeleton variant="circular" width={32} />
<WildSkeleton variant="text" width="58%" height={12} />
<WildSkeleton variant="text" width="36%" height={10} />
<WildSkeleton variant="rounded" width={64} height={24} radius={6} />
A row that loads into an avatar, two lines and a badge gets a skeleton for each.
<WildSkeleton variant="text" count={3} />
Three lines hold exactly three lines of body text, so the paragraph lands without a shift.

Accessibility

A skeleton is hidden from screen readers and takes no focus. Set aria-busy on the region that’s loading, and clear it when the content lands. The pulse stops under reduced motion.

Props

PropTypeDefaultDescription
variant'text' | 'circular' | 'rectangular' | 'rounded''text'A line, a circle, a square block or a rounded block.
widthnumber | string—Defaults to 100%, or 40px for circular.
heightnumber | string—Defaults to 16, 40 or 100px by variant.
radiusnumber | string—Overrides the variant corner.
countnumber1Repeats the skeleton in a column.
animation'pulse' | 'none''pulse'Pulse, or a still block.
styleCSSProperties—Extra inline styles, applied last.

Tokens

TokenValueWhere it lands
--global-neutral-grey-300#F1F1F1The fill.
--radius-sm4pxText corners.
--radius-lg8pxRounded corners, by default.
--radius-none0Rectangular corners.
--radius-full9999pxCircular corners.
(no token)1500msOne pulse cycle.