Skip to main content

Skeleton

Holds the shape of content that has not arrived yet.

import { Skeleton } from "@/fragments/ui";Source

Preview

<Skeleton width={200} height={20} />

Installation

npx @usefragments/cli add skeleton

Writes src/fragments/ui/components/Skeleton plus what it imports, the globals stylesheet, and .fragments/registry-lock.json, then prints the packages to add. No account, no key.

Your own registry: publish from Fragments Cloud and add --registry org/name. Connect a workspace.

Anatomy

Skeleton is a compound: import the root and reach its parts through dot notation.

  • Skeleton.Text
  • Skeleton.Circle

Examples

Text Lines

Stacked lines that fill the width they are given.

<div style={{ width: 260 }}>
  <Skeleton.Text lines={3} />
</div>

Semantic Shapes

Heading sits taller than the body lines under it.

<div
  style={{
    width: 260,
    display: 'flex',
    flexDirection: 'column',
    gap: 'var(--fui-space-2)',

Avatar Skeleton

Circles matching the three avatar sizes.

<div style={{ display: 'flex', gap: 'var(--fui-space-1)', alignItems: 'center' }}>
  <Skeleton.Circle size="sm" />
  <Skeleton.Circle size="md" />
  <Skeleton.Circle size="lg" />
</div>

Card Skeleton

Media, title, then body — the card before it loads.

<div
  style={{
    width: 300,
    padding: 'var(--fui-space-2)',
    border: '1px solid var(--fui-border)',
    borderRadius: 'var(--fui-radius-lg)',

API

Component props
Prop
Type
Default
Description
shapeenumtextheadingavatarbuttoninputrectrectSemantic shape that auto-sizes
sizeenumsmmdlgmdSize for avatar/button shapes
widthunionNot setCustom width (string or number)
heightunionNot setCustom height (string or number)
fillbooleanfalseFill parent container
radiusenumsmmdlgnonefullNot setBorder radius override
staticbooleanfalseDisable skeleton animation

Accessibility

  • Skeletons are decoration — hide them with aria-hidden
  • Announce the loading state separately if it matters
  • Keep the pulse subtle but visible against the surface

Guidance

Use when

  • Content is still being fetched
  • You want to stop the layout jumping when it lands
  • Making a wait feel shorter than it is

Avoid when

  • Waits under about 300ms
  • A spinner says it better
  • Work the user cannot see anyway
  • ProgressalternativeUse Progress for determinate loading

Next steps