Getting started
Install bones and render your first skeleton.
Installation
npm install @lovo/bonesImport the CSS
Bones needs a small CSS file for skeleton visuals. Import it once in your root layout or entry point:
import "@lovo/bones/css";Basic usage
Pass data (or a promise of data) to createBones. Spread the bone function's return value onto elements that should show skeletons while loading.
import { createBones } from "@lovo/bones";
function ProfileCard({ user }: { user: Promise<User> | User }) {
const { bone, data, lines } = createBones(user);
return (
<div>
<img src={data?.avatar} width={80} height={80} {...bone("block")} />
<h3 {...bone("text", { length: 10 })}>{data?.name}</h3>
{lines(data?.bio, 3, (item) => (
<p>{item}</p>
))}
</div>
);
}Add a Suspense boundary
Wrap components that receive promises in <Bones>. It creates a Suspense boundary and generates the skeleton fallback for you:
import { Bones } from "@lovo/bones";
export default function Page() {
return (
<Bones>
<ProfileCard user={fetchUser()} />
</Bones>
);
}While the promise is pending, <Bones> renders the same <ProfileCard> tree with skeletons visible. Once it resolves, the real content swaps in.
Bone types
| Type | Use for | Example |
|---|---|---|
"text" | Headings, paragraphs, labels | <h2 {...bone("text")}> |
"block" | Images, avatars, thumbnails | <img src={…} {...bone("block")} /> |
"container" | Wrappers with complex children | <div {...bone("container")}> |
Previewing skeletons
Use forceBones to see a component's skeleton state without setting up real data:
import { createBones, forceBones } from "@lovo/bones";
// Pass forceBones in place of any promise prop:
<ProfileCard user={forceBones} />;To force an entire subtree into skeleton mode at once, wrap it with <BonesForce>:
import { BonesForce } from "@lovo/bones";
<BonesForce>
<ProfileCard />
<PostList />
</BonesForce>;Neither approach needs a Suspense boundary or async data. Just render and you'll see skeletons immediately. Useful for tweaking styles or demoing loading states in Storybook.