Skeleton
A loading placeholder that mirrors the shape of the content it stands in for. Single-element like Badge; the fill is a semantic token, so it re-themes everywhere, and the optional shimmer rides the shared motion tokens.
Installation#
Usage#
import { Skeleton } from "@/components/ui/skeleton"
export function Example() {
return <Skeleton className="h-8 w-48" />
}Variants#
Three shapes cover most placeholders. rectangle is the default block; circle takes a single size-* for avatars and icons; and text matches the surrounding line-height exactly via the 1lh unit.
Multi-line text#
Pass lines with variant="text" to render a paragraph-shaped block. The last line wraps short, the way real running text does.
Animation#
pulse (the default) breathes opacity; shimmer sweeps a highlight driven by the --animate-shimmer motion token; and none holds a static placeholder. All three stop under prefers-reduced-motion.
Composition#
Skeletons are layout primitives; compose them to trace the real content. Wrap the loading region in aria-busy="true" so the placeholders (each aria-hidden) stay silent to screen readers while one status is announced for the whole region.
API reference#
Skeleton
A decorative aria-hidden placeholder; set aria-busy on the loading region instead. Forwards all native <div> props and accepts className, merged last.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "rectangle" | "circle" | "text" | "rectangle" | Shape: a rounded block, an aspect-square circle sized by one size-*, or a full-width line one 1lh tall. |
| animation | "pulse" | "shimmer" | "none" | "pulse" | Opacity breathe, a swept highlight on the --animate-shimmer token, or static. Both animations stop under prefers-reduced-motion. |
| lines | number | - | With variant="text", stacks this many lines (the last at 60% width); className then styles the group. Ignored for other variants and for lines <= 1. |