Skip to content

Skeleton

  • Lists, cards and profiles while their data loads
  • Keeping the layout still, so content does not jump in

Not for work with no visible result yet — use a Spinner — or when the shape of the content is unknown.

Choosing between showing progress, loading or a measurement:

ComponentUse it forFor example
ProgressA task whose completion is known, moving toward doneUpload at 40%, step 2 of 5
StepperThe named steps of a multi-step flow, and which one you’re onCheckout: Cart, Shipping, Payment
MeterA measurement within a known range, not a taskDisk usage, password strength, a score
SpinnerWork of unknown length, in a small spaceA button saying “Saving…”, a panel refreshing
SkeletonContent still loading whose shape is known, so the layout does not jumpPlaceholder rows in a list, a profile card
import { Skeleton } from '@arun-dev/ui';
// aria-busy on the region it stands in for: the Skeleton itself is hidden. A named <section>
// is a region, so it can carry the label.
export default function SkeletonBasics() {
return (
<section
aria-busy="true"
aria-label="Loading profile"
style={{ display: 'flex', gap: 'var(--space-sm)', alignItems: 'center', inlineSize: '20rem' }}
>
<Skeleton
style={{ inlineSize: '3rem', blockSize: '3rem', borderRadius: 'var(--radius-full)' }}
/>
<div style={{ display: 'grid', gap: 'var(--space-2xs)', flex: 1 }}>
<Skeleton style={{ inlineSize: '60%' }} />
<Skeleton style={{ inlineSize: '90%' }} />
</div>
</section>
);
}

Skeleton is a shape that stands in for content while it loads. It is hidden from screen readers. Mark the region it fills with aria-busy="true" instead, and remove that once the content arrives.

Its size and shape are yours, set with style or a class. It is one line of text high by default. The shine stops under reduced motion.

Skeleton props
PropTypeDefaultDescription
classNamestringConcatenated with the component's own classes, never replacing them.
renderReactElementElement or component to render instead of the default. Props, className, event handlers and ref are merged onto it.
refRef<HTMLElement>Ref to the rendered element. Merged with any ref on the render element.
…restHTMLAttributesAnything else is spread onto the rendered element, so id, aria-*, data-* and event handlers all reach the DOM.