Skeleton

Loading placeholder block that respects reduced motion.

atomsSource
import { Skeleton } from '@elirobinson/react/components/atoms/Skeleton';

Styles: @elirobinson/react/styles/atoms/Skeleton.css — already included when you import @elirobinson/react/styles.css.

Show code
import { Skeleton } from '@elirobinson/react/components/atoms/Skeleton';

export default function Basic() {
  return <Skeleton style={{ width: 240, height: 20 }} />;
}

When to use it

Use Skeleton for a structural loading placeholder that mimics the shape of the content about to appear — it cuts layout shift and signals progress visually. Use Spinner instead for a small, content-agnostic "working" indicator, and Progress when you actually know the percent complete.

Composing a loading card

Stack skeletons to match the real content's layout — an image block, a title line, a subtitle line.

Show code
import { Skeleton } from '@elirobinson/react/components/atoms/Skeleton';

export default function Card() {
  return (
    <div className="demo-col" aria-label="Loading coaching guides" role="status">
      <Skeleton style={{ height: 160 }} />
      <Skeleton style={{ height: 16, width: '80%' }} />
      <Skeleton style={{ height: 14, width: '60%' }} />
    </div>
  );
}

Props

Skeleton has no props of its own — size and shape come from className/style on the inherited HTMLAttributes<HTMLDivElement>.

No props of its own beyond the inherited HTML attributes.

Also accepts all HTMLAttributes<HTMLDivElement> props.

Accessibility

  • Always renders with aria-hidden="true" — it's invisible to screen readers by design, meaning it does not announce a loading state to assistive tech on its own.
  • If the wait is long enough to matter, pair it with a role="status" wrapper or visually-hidden text (see the card demo above), or use Spinner, which already carries role="status".
  • The pulse animation respects prefers-reduced-motion — not through a per-component check, but because the design tokens stylesheet flattens all animation and transition durations globally when that preference is set.

Do

  • Shape skeletons to match the real content’s dimensions so the swap-in doesn’t jump.
  • Stack multiple Skeletons to represent a whole loading card, mirroring the real layout.
  • Pair it with a role="status" wrapper or screen-reader-only text when the wait genuinely needs to be announced.

Don't

  • Rely on Skeleton alone to tell screen reader users something is loading — it’s aria-hidden, silent by design.
  • Leave skeletons on screen indefinitely if a request fails — swap to an error state, don’t strand the pulse.
  • Use Skeleton for a single small icon-sized loading state — Spinner reads better at that scale.