Skeletons that draw themselves.

skelly reads your rendered UI and generates pixel-accurate loading states for it — components, pages, images, text, tables. Shimmer, pulse, or optimistic. On the server too.

$npm i skelly
Read the docs →
2.1 kB gzip·zero deps·MIT
loading — skeleton by skelly
Amara Osei
Posted 2 hours ago
Follow
Shipped the new onboarding flow today. Conversion is up 12% and the skeleton states made the whole thing feel instant — even on 3G.
cover image
♥ 248↻ 31✉ 12
← one component. skelly generated the skeleton. →
01 — wrap
<Skelly loading={isLoading}>
  <ProfileCard />
</Skelly>

Wrap anything — a button, a table, an entire page.

02 — analyze
▸ 1 avatar (circle)
▸ 3 text lines (61–100%)
▸ 1 image block

skelly measures the real layout — shapes, radii, line lengths.

03 — render

A matching skeleton renders instantly — client or server.

Every loading state. One API.

Pick a visual per component or set one globally. All of them respect prefers-reduced-motion.

Shimmer
GPU-composited sweep. The classic.
Pulse
Quieter. Great for dense tables.
"Untitled draft" ✓ saved
Optimistic
Render expected data, reconcile on arrival.
HTML → skeleton inlined
SSR / streaming
Skeletons in the first byte. No hydration flash.
Whole pages
Route-level snapshots generate full-page skeletons at build time.
Text-aware
Line count and ragged-edge widths match your real copy.
Images & media
Aspect-ratio-locked blocks. Optional dominant-color fill.
Tables & lists
Row-count hints; sticky headers stay real while cells load.

Your framework. Or none.

The core is vanilla — 2.1 kB, framework-agnostic. Thin adapters where you want idioms.

import { Skelly } from 'skelly/react'

<Skelly loading={isLoading} visual="shimmer">
  <ProfileCard user={user} />
</Skelly>

Stop hand-rolling gray boxes.

// hand-rolled skeletons
One skeleton component per real component — forever out of sync
Redesign a card, forget its skeleton, ship the layout jump
Client-only — blank page until hydration
Every dev invents their own shade of gray
// with skelly
Skeletons derived from the component itself — can't drift
Zero layout shift: same box, same size, guaranteed
SSR + streaming: skeletons arrive with the HTML
One theme token; matches your design system automatically

Small enough to not think about.

Bundle size, minified + gzip. Core only; adapters add ~0.4 kB.

skelly
2.1 kB
react-loading-x
8.9 kB
placeholder-ui
13.6 kB
hand-rolled (avg)
26+ kB

Live Performance Benchmark

Test Skelly's layout-compiling speed on your current browser CPU thread.

0 ms
layout shift (CLS) introduced
< 1 ms
analysis per component, cached
100%
GPU-composited animations

Ship the skeleton, not the spinner.

$npm i skelly