Skip to content

Skeleton

A grey placeholder shaped like the content that is loading, so the page doesn't jump when it arrives.

Feedbackv0.1.0experimentalWCAG 2.2 AAView spec
import { Skeleton } from "@rdloom/react";

export default function SkeletonTextExample() {
  return (
    <div className="w-80 max-w-full">
      <Skeleton variant="text" lines={3} />
    </div>
  );
}

Installation

npx rdloom add skeleton

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/skeleton.json

Works, but without upgrade tracking.

Usage

import { Skeleton } from "@rdloom/react";

<div className="w-80 max-w-full">
  <Skeleton variant="text" lines={3} />
</div>

Card

Loading project
import { Skeleton } from "@rdloom/react";

// The loading region says it is busy; the placeholders themselves are silent.
export default function SkeletonCardExample() {
  return (
    <div aria-busy="true" className="flex w-80 max-w-full flex-col gap-3">
      <span role="status" className="sr-only">
        Loading project
      </span>
      <Skeleton variant="rect" height={120} />
      <Skeleton variant="text" lines={2} />
    </div>
  );
}

Avatar row

Loading contact
import { Skeleton } from "@rdloom/react";

export default function SkeletonAvatarRowExample() {
  return (
    <div aria-busy="true" className="flex w-80 max-w-full items-center gap-3">
      <span role="status" className="sr-only">
        Loading contact
      </span>
      <Skeleton variant="circle" width={40} />
      <div className="flex-1">
        <Skeleton variant="text" lines={2} />
      </div>
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
variant

text is a line (or lines) of text, rect a block like an image, circle an avatar.

"text" | "rect" | "circle""rect"
width

CSS width: a number is px, a string is any CSS length, e.g. '60%'. Text lines default to full width; the last of several is shorter.

string | numbernone
height

CSS height. Text uses the text's line height; rect defaults to 96px.

string | numbernone
lines

For text: how many lines to draw.

number1

Accessibility

Role none, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

Not interactive.

Screen readers announce

  • Skeletons themselves are silent; the loading region's status message (e.g. "Loading orders") is what is heard

What your code must do

  • It is hidden from assistive technology (aria-hidden): there is nothing to read
  • Mark the loading region with aria-busy="true" and tell screen readers it is loading with a visually hidden status message
  • The pulse animation stops for people who prefer reduced motion

Guidelines

Use it when

  • Loading content whose shape is known: lists, cards, profiles
  • Avoiding layout shift when data arrives

Avoid it when

  • Unknown shape or a short wait: use a spinner
  • Long operations with measurable progress: use Progress

Don't

  • Skeletons that don't match the real layout
  • Leaving them up with no loading message for screen readers

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-surface-subtle
  • --rd-radius-control