bones

Getting started

Install bones and render your first skeleton.

Installation

npm install @lovo/bones

Import 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

TypeUse forExample
"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.

On this page