Getting Started

Add skeleton loading screens to any React app in under 5 minutes. No config files, no build plugins.

1. Install
bash
npm install boneyard-js

Also works with yarn add boneyard-js or pnpm add boneyard-js.

2. Wrap your component
app/blog/page.tsx
import { Skeleton } from 'boneyard/react'

function BlogPage() {
  const { data, isLoading } = useFetch('/api/post')

  return (
    <Skeleton name="blog-card" loading={isLoading}>
      {data && <BlogCard data={data} />}
    </Skeleton>
  )
}

Give each skeleton a name — this is what the CLI uses to identify it and generate the bones file.

If your component needs data from an API or is behind authentication, add a fixtureprop with mock content. The CLI renders the fixture during capture — your real data isn't needed:

app/blog/page.tsx
<Skeleton
  name="blog-card"
  loading={isLoading}
  fixture={<BlogCard data={{
    title: "Sample Post",
    excerpt: "Placeholder text for layout...",
    author: "Jane Doe"
  }} />}
>
  {data && <BlogCard data={data} />}
</Skeleton>

Notes

  • Next.js App Router: <Skeleton> uses hooks — add "use client" to any file that imports it.
  • Data-dependent components: If your component needs API data to render, use the fixture prop to provide mock content for the build step. The fixture is only rendered during npx boneyard-js build — never in production.
3. Generate bones

With your dev server running, run the CLI. It visits your app at multiple viewport widths, snapshots every named <Skeleton>, and writes a .bones.json file for each one.

bash
npx boneyard-js build

Auto-detects your running dev server by scanning common ports (3000, 5173, 4321, 8080…). Captures at 375px, 768px, and 1280px by default.

Playwright is included as a dependency. On first run you may need to install the browser: npx playwright install chromium

Apps with authentication

The build CLI uses a headless browser to visit your app. If your pages require login, you have a few options:

  • Use the fixture prop — provide mock data so the CLI can capture bones without needing real user sessions. This is the recommended approach.
  • Run against a dev server with auth disabled — many frameworks support an environment flag to bypass auth in development.
  • Point the CLI at public pages— if your login/onboarding pages don't require auth, capture those directly and use fixtures for authenticated pages.
4. Register bones

The build generates a registry.js file alongside your bones. Add this one-line side-effect import to your app entry and every <Skeleton> auto-resolves its bones by name.

app/layout.tsx (or your entry file)
import './bones/registry'

That's it. Your component stays clean — no per-file JSON imports needed:

app/blog/page.tsx
import { Skeleton } from 'boneyard/react'

function BlogPage() {
  const { data, isLoading } = useFetch('/api/post')

  return (
    <Skeleton name="blog-card" loading={isLoading}>
      {data && <BlogCard data={data} />}
    </Skeleton>
  )
}

boneyard picks the nearest breakpoint for the current viewport width. Re-run npx boneyard-js build any time your layout changes to regenerate.

Manual override

You can still pass initialBones directly if you prefer per-component imports. It takes precedence over the registry when provided.

Your project after setup
your-app/
├── src/
├── bones/ ← generated by npx boneyard-js build
├── blog-card.bones.json
├── profile.bones.json
├── dashboard.bones.json
└── registry.js ← import once in your entry file
├── app/
├── layout.tsx ← import './bones/registry'
├── blog/
└── page.tsx
└── dashboard/
└── page.tsx
└── components/
├── BlogCard.tsx
└── Dashboard.tsx
├── package.json
└── node_modules/
└── boneyard/

The bones/ directory is auto-detected. If you have a src/ folder it goes to src/bones/, otherwise ./bones/. Override with --out.

Customization

Custom bone color

tsx
<Skeleton loading={isLoading} color="#c8b4f0">

Static skeleton (no pulse animation)

tsx
<Skeleton loading={isLoading} animate={false}>

Custom breakpoints + output directory

bash
npx boneyard-js build --breakpoints 390,820,1440 --out ./public/bones

Next steps

  • See API Reference for all props and snapshot config options
  • Try the Playground to see live bone extraction
  • Browse Examples — blog cards, product grids, dashboards, chat threads