How it works

What happens when you wrap a component with <Skeleton>.

Your component
localhost:3000

Understanding Modern Web Performance

Layout shift occurs when visible elements move during page load.

Sarah Chen
Generated skeleton
localhost:3000

Understanding Modern Web Performance

Layout shift occurs when visible elements move during page load.

Sarah Chen
Under the hood

Boneyard generates skeletons at build time — not at runtime. Here's the three-step flow:

1. Wrap

Wrap your component with <Skeleton name="blog-card" loading={isLoading}>. When loading is false, your children render normally.

localhost:3000

Understanding Modern Web Performance

Layout shift occurs when visible elements move during page load.

Sarah Chen

2. Build

Run npx boneyard-js build. This launches a headless browser via Playwright, visits your running app at multiple breakpoints, and calls getBoundingClientRect() on every visible element inside each named <Skeleton>. The exact pixel positions, sizes, and border radii are written to .bones.json files and a registry.js that maps each skeleton name to its bones.

localhost:3000

Understanding Modern Web Performance

Layout shift occurs when visible elements move during page load.

Sarah Chen

3. Render

Import the generated registry once in your app entry. When loading is true, boneyard looks up the pre-generated bones by name and renders them as gray rectangles — each one an absolutely positioned div matching the exact position from the real layout. When loading becomes false, your children replace the skeleton with zero layout shift.

localhost:3000

Understanding Modern Web Performance

Layout shift occurs when visible elements move during page load.

Sarah Chen

Run npx boneyard-js build to pre-generate bones, then add import './bones/registry' to your app entry. Every <Skeleton name="..."> auto-resolves its bones from the registry — no per-component imports needed.