Getting Started
Add skeleton loading screens to any React app in under 5 minutes. No config files, no build plugins.
npm install boneyard-jsAlso works with yarn add boneyard-js or pnpm add boneyard-js.
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:
<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
fixtureprop to provide mock content for the build step. The fixture is only rendered duringnpx boneyard-js build— never in production.
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.
npx boneyard-js buildAuto-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
fixtureprop — 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.
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.
import './bones/registry'That's it. Your component stays clean — no per-file JSON imports needed:
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.
The bones/ directory is auto-detected. If you have a src/ folder it goes to src/bones/, otherwise ./bones/. Override with --out.
Custom bone color
<Skeleton loading={isLoading} color="#c8b4f0">Static skeleton (no pulse animation)
<Skeleton loading={isLoading} animate={false}>Custom breakpoints + output directory
npx boneyard-js build --breakpoints 390,820,1440 --out ./public/bonesNext 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