Skip to main content

Skeleton

A skeleton is a placeholder for content that is loading. By rendering a neutral block where real content will eventually appear, you give the user an early sense of layout and reduce both perceived loading time and Cumulative Layout Shift (CLS).

When to use

  • Async-loaded content where the eventual shape is predictable (lists, cards, tables, avatars).
  • On initial page load, before data has resolved.

For a whole list page, the List Page Loading States recipe shows where the skeleton belongs and what renders around it.

When not to use

  • For very short fetches (under ~200 ms) — a flash of skeleton is more distracting than helpful.
  • To convey error or empty states. Use Empty instead.
  • As a permanent decorative shape.

Sizing

Default height is 1rem. Override className with h-*, w-*, and rounded-* utilities to match the real content's dimensions — the more closely the skeleton matches, the less layout shift on swap.

Accessibility

Skeletons are decorative and convey no semantic meaning to assistive tech, so Skeleton renders aria-hidden="true" by default. Pass aria-hidden={false} to opt out. If the underlying region is loading, also announce it to screen readers, for example wrap it in an element with role="status" and a visually-hidden "Loading…" label.

Loading profile…
import { Skeleton } from "@ngrok/mantle/skeleton"; <div role="status" aria-live="polite">	<span className="sr-only">Loading profile…</span>	<Skeleton className="h-12 w-12 rounded-full" /></div>;
import { Skeleton } from "@ngrok/mantle/skeleton"; <Skeleton className="w-full" />;

Examples

Composition: Skeleton within a Media Object

Include the Skeleton within other components. Pass Tailwind utility classes for further control.

import { MediaObject } from "@ngrok/mantle/media-object";import { Skeleton } from "@ngrok/mantle/skeleton"; <MediaObject.Root className="w-full max-w-96 items-center">	<MediaObject.Media>		<Skeleton className="h-12 w-12 rounded-full" />	</MediaObject.Media>	<MediaObject.Content className="space-y-3">		<Skeleton className="w-full" />		<Skeleton className="w-4/5" />	</MediaObject.Content></MediaObject.Root>;

Polymorphism

Skeleton accepts an asChild prop. When true, it renders its single child instead of its default <div>, forwarding its class names, data-* attributes, and ref onto that child. Reach for this when the placeholder should also be a more semantic element.

import { Skeleton } from "@ngrok/mantle/skeleton"; <Skeleton asChild className="h-12 w-12 rounded-full">	<span /></Skeleton>;

API Reference

Skeleton

The Skeleton accepts the following props in addition to the standard HTML div attributes.

PropTypeDefaultDescription
asChild?booleanfalseUse the asChild prop to compose the Skeleton styling and functionality onto alternative element types or your own React components.