Skip to main content
Markdown

Skeleton

Skeleton renders a visual placeholder for content that is still loading. Use it when the final layout is known enough to reserve space and avoid a jumpy transition when data arrives.

The component is decorative by default and renders aria-hidden="true". Pair it with surrounding loading text, a region state, or another status component when the loading state needs to be announced.

Usage

import { Skeleton } from '@takeoff-ui/react-spar';
<Skeleton height={16} width="60%" />
<Skeleton shape="circle" height={40} />

Playground


function PlaygroundDemo() {
  return (
    <div className="mx-auto flex w-full max-w-120 flex-col gap-4">
      <div className="flex items-center gap-3">
        <Skeleton shape="circle" height={48} />
        <div className="flex flex-1 flex-col gap-2">
          <Skeleton height={16} width="45%" />
          <Skeleton height={14} width="70%" />
        </div>
      </div>
      <Skeleton height={120} />
      <div className="flex flex-col gap-2">
        <Skeleton height={14} />
        <Skeleton height={14} width="88%" />
        <Skeleton height={14} width="62%" />
      </div>
    </div>
  );
}

render(<PlaygroundDemo />);

Shapes

shape="rectangle" renders a rounded bar. shape="circle" turns the root into a full-radius disc whose diameter follows height.


function ShapesDemo() {
  return (
    <div className="flex flex-wrap items-center justify-center gap-8">
      <div className="flex w-64 flex-col gap-3">
        <Skeleton height={20} />
        <Skeleton height={20} width="80%" />
        <Skeleton height={20} width="55%" />
      </div>
      <Skeleton shape="circle" height={72} />
    </div>
  );
}

render(<ShapesDemo />);

Sizing

width and height accept numbers in pixels or any CSS length string. Omitting width lets the placeholder fill its container.


function SizingDemo() {
  return (
    <div className="mx-auto flex w-full max-w-120 flex-col gap-3">
      <Skeleton height={12} width="35%" />
      <Skeleton height={16} width="60%" />
      <Skeleton height={24} width={320} />
      <Skeleton height="4rem" width="100%" />
    </div>
  );
}

render(<SizingDemo />);

Animation

Use animation="none" for static placeholders, especially inside surfaces where motion would distract from other loading or status indicators.


function AnimationDemo() {
  return (
    <div className="mx-auto grid w-full max-w-120 gap-5 sm:grid-cols-2">
      <div className="flex flex-col gap-3">
        <Skeleton height={18} width="45%" />
        <Skeleton height={80} />
        <Skeleton height={14} width="70%" />
      </div>
      <div className="flex flex-col gap-3">
        <Skeleton animation="none" height={18} width="45%" />
        <Skeleton animation="none" height={80} />
        <Skeleton animation="none" height={14} width="70%" />
      </div>
    </div>
  );
}

render(<AnimationDemo />);

Accessibility

  • Skeleton is hidden from assistive technology by default because it does not carry meaningful content on its own.
  • Announce loading through nearby copy, a labeled region with aria-busy, or a Spinner when users need active status feedback.
  • Avoid replacing labels, headings, or controls with focusable placeholders. Render the real interactive element only when it is ready.

API Reference

Skeleton

Props

NameTypeDefaultDescription
shapeSkeletonShape'rectangle'Placeholder silhouette. rectangle renders the rounded bar, circle a full-radius disc whose diameter tracks height.
animationSkeletonAnimation'shimmer'Loading animation. shimmer sweeps the highlight strip across the bar; none renders a static placeholder.
widthstring | number-Fixed width, number in px or any CSS length. Published to the recipe as --tk-skeleton-width; defaults to filling the container.
heightstring | number-Fixed height, number in px or any CSS length. Published to the recipe as --tk-skeleton-height.
classNamesPartial<Record<SkeletonSlot, string>>-Per-slot extra classes.
slotPropsPartial<Record<SkeletonSlot, React.HTMLAttributes<HTMLElement>>>-Per-slot HTML-attribute overrides.
classNamestring-Appends custom classes to the root slot.
aria-hiddenboolean | "true" | "false"trueKeeps the placeholder out of the accessibility tree. Leave it hidden and expose loading context through nearby content.

Data attributes

AttributeApplied whenPurpose
data-slot="root"AlwaysStable selector for wrapper styling on the root slot.
data-typeAlwaysReflects the resolved shape prop for theme recipe scoping.
data-animationAlwaysReflects the resolved animation prop for theme recipe scoping.
data-slot="shimmer"Always on the inner spanStable selector for the decorative shimmer strip.

Type Definitions

NameDefinition
SkeletonShape'rectangle' | 'circle'
SkeletonAnimation'shimmer' | 'none'
SkeletonSlot'root' | 'shimmer'