Skeleton to Content
Breathing placeholders hand off to the real content in one cross-fade and a small lift.
The animated component in this preview is rendered from the canonical file shown here. The surrounding demo shell only provides context and is not part of the copied code.
import { useEffect, useState } from "react";
import type { CSSProperties, ReactNode } from "react";
import { motion, useReducedMotion } from "motion/react";
/**
* Vibary · Skeleton to Content
*
* Placeholder blocks breathe while data is in flight, then the realAbout this pattern
The default loading state for anything that fetches: feeds, dashboards, profile panels. Placeholder blocks breathe on a slow cycle so the surface reads as alive rather than frozen, then the real content cross-fades over them and lifts a few pixels into place. Placeholder and content share a single grid cell, so the panel is already the right size before the data lands — the hand-off never shoves the rest of the page around, which is what separates this from simply swapping one block for another.
Where it shows up
Screens we drew to show where this motion usually sits. Illustrations, not captures of any product.
- Photo gallery
Grey placeholders on the home grid resolve into thumbnails and titles.
Related patterns
- Table Rows PopulatePlaceholder cells resolve one column at a time, so the eye follows the fill instead of hunting for it.
- Search Results SwapStale answers dim and stay put while the fresh set cross-fades over them.
- Content Placeholder PulsePlaceholder blocks rise and fall together on one slow cadence, so the region reads as dormant rather than busy.
