Content
- No text. A skeleton says nothing; the shapes do.
A grey placeholder shaped like content that hasn't loaded yet.
import { … } from "@brdgapp/ui/components/skeleton"Skeleton is a grey placeholder shaped like content that hasn't loaded yet: a text line, a circle for a face, or a block. Build a loading state from skeletons the same size and shape as the real content, so nothing moves when the data arrives. The usual mistake is one big spinner, or skeletons that don't match what replaces them.
skeleton.The look comes from props
A component's appearance comes only from its own options (variant, size, color). className on a package component is for layout (mt-4, shrink-0, w-full), never for font size, color, padding, radius or hover. If the look needs a className, the component or the chosen option is wrong: fix that instead.
Each part loads on its own
The page frame shows straight away; each card, table or list shows its own skeleton, then its data. Never hold the whole page behind one if (isLoading) return <Skeleton />: a slow part would block the fast ones.
Reserve the space
Nothing that arrives later may push content down. A skeleton has the same height and shape as what it stands for, measured, not guessed. A visible jump after the first paint is a bug.
Line. 12px tall, 4px corners. Give it a width (w-1/2, w-24) and, for bigger text, a height (h-4).
Circle. Round. Give it a size matching the face or logo it stands in for (size-8).
Block. 12px corners. Give it the size of the chart, image or card body it stands in for.
The same rows, faces and lines the real list will have. The card and title stay.
| State | What happens |
|---|---|
| Loading | --surface-tertiary, pulsing gently. With reduced motion, it stays still. |
aria-hidden); the region that's loading says so, which DataState sets up.shape; size and position from className (w-1/2, size-8, h-24). Never a color or a corner through className.Do
Draw the same rows, faces and lines the content will have, at the same sizes.Don't
Show one generic block, or a spinner, where a list of people will appear.Do
Keep the card and its title on screen; only the inside is skeletons.Don't
Replace the whole card, title and all, with a grey box.Skeleton
One placeholder shape.
| Prop | Type | Default | Description |
|---|---|---|---|
shape | "line" | "circle" | "block" | "line" | Text line (4px corners), circle, or block (12px corners). |
className | string | — | Size and position only: w-1/2, size-8, h-24. |
What it's built from and where it's used, read from the code. When you change it, check these too.
skeleton (Base UI style), pulled with npm run ui-add, then put on Bridge's token.bg-[var(--surface-tertiary)] animate-pulse placeholders in 40 files (main, 5d9b382).