A loading placeholder with shimmer or fade variants, plus a transition that crossfades into real content once loading finishes. React component.
Made by AxylA cover image (fade) above a profile row (shimmer) that crossfades into content once ready.
Use SkeletonAvatar, SkeletonText, and SkeletonButton for common shapes — they accept all
Skeleton props (SkeletonAvatar/SkeletonButton fix rounded to their own shape, so that
one prop isn't available on those two):
ShimmerSkeleton is an alias for Skeleton (same component, same props) — pick whichever
name reads better at the call site.
variant="shimmer" (default) sweeps a moving highlight; variant="fade" uses Tailwind
animate-pulse for a calmer opacity pulse — a good fit for large blocks like cover images
or cards:
There's no color or background prop — Skeleton reads two CSS variables instead:
--sk-muted for the surface fill and --sk-foreground for the shimmer highlight. Both
default to your app's own --muted / --foreground shadcn tokens when present, so it
matches your theme automatically. Override either directly to use different colors:
Plain Tailwind background utilities (bg-accent, etc.) also work for the surface fill since
className is merged last, but the shimmer highlight only follows --sk-foreground — override
both if you want the two to stay in sync.
Wrap a placeholder and the real content in SkeletonTransition — when loading flips to
false, the shimmer settles for a beat, then the skeleton and content crossfade:
Tune the pacing with settleDuration (how long the skeleton lingers once loading turns
false, before the crossfade starts) and fadeDuration (the crossfade itself), both in seconds:
Size skeleton to match content
While both are mounted, children is absolutely positioned over skeleton, which drives
the wrapper's height. If the two differ a lot in size, the layout snaps to the content's
real height the instant the crossfade finishes. Keep skeleton close to the real content's
dimensions to avoid a visible jump.
| Prop | Type | Default |
|---|---|---|
variant? | "shimmer" | "fade" | "shimmer" |
duration? | number | 1.6 (shimmer) / 2.4 (fade) |
rounded? | "none" | "sm" | "md" | "lg" | "full" | "md" |
animate? | boolean | true |
decorative? | boolean | true |
label? | string | null | - |
| Prop | Type | Default |
|---|---|---|
loading? | boolean | - |
skeleton? | ReactNode | - |
children? | ReactNode | - |
className? | string | - |
settleDuration? | number | 0.4 |
fadeDuration? | number | 0.15 |
Use Skeleton for content that loads asynchronously and has a roughly known shape ahead of
time — profile cards, list rows, article previews. It reduces perceived load time better
than a spinner because it previews the coming layout. Reach for SkeletonTransition whenever
the loading state and the real content live in the same spot, so the swap reads as one
continuous moment instead of a layout jump.
By default, Skeleton is aria-hidden — a purely decorative placeholder alongside content
that's coming. Set decorative={false} to announce it as a live loading status
(role="status", aria-live="polite") when there's no other loading indicator on the page.
When prefers-reduced-motion: reduce is set, shimmer animation stops (injected CSS is
disabled), fade uses motion-reduce:animate-none, and SkeletonTransition skips its settle
delay and crossfades immediately.
Pixel Image Loader
A canvas-based image that resolves from a blocky, pixelated placeholder up to full sharpness as it loads. React component.
Skeleton Shimmer
GPU-accelerated shimmer placeholder primitives with zero-layout-shift sizing and optional View Transitions API wipe reveals.
Built by Axyl. A motion-first component registry for React.
Last updated: 9/14/2026
Help keep SoraLabs moving.
Every contribution helps us build and maintain open-source tools for the community.
Sponsor on GitHub