Skip to content

Skeleton

Loading placeholder drawn as a strip of character cells with a left-to-right scan sweep. Purely decorative (aria-hidden). Size it in cells with chars, or set dimensions via className.

Preview

Installation

$pnpm exec dgadd add ui/skeleton
[Installs to]src/components/ui/skeleton[Item]ui/skeleton

dgadd is not public on npm yet. Until the first release, pack @diffgazer/add from the repository and install that tarball into this app, which is what puts dgadd on pnpm exec.

UI components require Tailwind CSS v4. Local copy mode imports src/styles/styles.css; package mode uses @diffgazer/ui CSS once packages are available.

Usage

tsx
import { Skeleton } from "@/components/ui/skeleton";export default function SkeletonDefault() {  return (    <div className="flex flex-col gap-3 w-64">      {/* chars reserves the width of the value each row stands in for: a          7-character sha next to a 12-character path. */}      <div className="flex items-center gap-3">        <Skeleton chars={7} className="h-4" />        <Skeleton chars={12} className="h-4" />      </div>      <Skeleton className="h-4 w-full" />      <Skeleton className="h-4 w-1/2" />    </div>  );}

Examples

Composed placeholder

Preview

API Reference

Skeleton

NameTypeDefaultDescription
charsnumberWidth of the placeholder in character cells, so it reserves the width of the value it stands in for. Surfaces as data-chars plus the --skeleton-chars custom property; omit and set width via className instead.
classNamestringClass names for the placeholder height and any width not set by chars.

Data attributes

AttributeApplies toValuesDescription
data-charsSkeletoncell count, present only when chars is setEnables the cell-count width rule that reads --skeleton-chars.

CSS variables

NameDefaultDescription
--skeleton-cell8pxWidth of one placeholder cell, including its gap.
--skeleton-gap1pxWidth of the knocked-out gap between two cells.
--skeleton-cell-fillcomponent-definedFill color of the cells. Deliberately below text contrast — the strip is decorative.

Accessibility

Notes

Dimensions

Skeleton has no intrinsic width. Pass chars to reserve the width of the value it stands in for (a 7-cell sha, a 40-cell path), or use Tailwind classes like w-32 h-4 for a proportional block. Height comes from className; the strip has a 12px floor so the cells stay legible.

Cell Grid

The strip is subdivided into --skeleton-cell wide cells by a mask, so it speaks the same character-cell alphabet as Spinner and BlockBar. The mask cuts the element's own background, which means a consumer background class still tiles into cells rather than filling the strip solid.

Reduced Motion

The scan sweep is dropped entirely under prefers-reduced-motion: reduce. The static cell grid still reads as pending.

Composition

Skeleton is one rectangle by design. Build a placeholder by composing several of them in the shape of the content being loaded — a square for an avatar, short bars for metadata, full-width bars for text — and keep the rhythm of the real layout so the swap to content does not jump.

Loading Announcements

Skeleton itself is decorative and aria-hidden. Put aria-busy on the region being loaded, or pair the loading state with a nearby status/live region when users need progress announced.

Source

Install via CLI: pnpm exec dgadd add ui/skeleton.

Highlighted source loads after this disclosure opens. Browse the source repository.