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#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add skeleton

Usage#

usage.tsxTSX
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.

PropTypeDefaultDescription
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.
linesnumber-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.

FAQ#

Use a Skeleton when you know the shape of the content that is loading, like a card or a list row, so the layout stays stable and there is no jump when the data arrives. A spinner is better for indeterminate, full-page waits where the eventual layout is unknown.