bones

Styling

Customize skeletons with CSS custom properties.

All skeleton visuals are controlled by CSS custom properties. Override them globally or scope them to a specific section.

CSS custom properties

PropertyDefault (light)Default (dark)Description
--bone-base#e0e0e0#2a2a2aSkeleton background color
--bone-highlight#f0f0f0#3a3a3aHighlight color (for shimmer)
--bone-radius4px4pxBorder radius of skeleton bars
--bone-duration1.5s1.5sAnimation duration

Theming

Override properties on any container to theme a section:

<div
  style={{
    "--bone-base": "#f5e6d3",
    "--bone-highlight": "#faf0e6",
    "--bone-radius": "8px",
  }}
>
  <UserCard user={forceBones} />
</div>

Or use a CSS class:

.warm-skeleton {
  --bone-base: #f5e6d3;
  --bone-highlight: #faf0e6;
}

Dark mode

Dark mode works via prefers-color-scheme:

@media (prefers-color-scheme: dark) {
  :root {
    --bone-base: #2a2a2a;
    --bone-highlight: #3a3a3a;
  }
}

Override these in your own dark mode styles if your app uses a class-based dark mode toggle.

Animations

Add data-bone-animate to any parent element to animate skeletons inside it:

  • shimmer - horizontal highlight sweep
  • pulse - gentle opacity fade (also kicks in automatically for prefers-reduced-motion: reduce)
{/* Animate a section */}
<div data-bone-animate="shimmer">
  <UserCard user={fetchUser()} />
</div>

{/* Animate the entire app */}
<body data-bone-animate="shimmer">

Speed is controlled by --bone-duration. Shimmer colors use --bone-base and --bone-highlight.

Accessibility

  • Skeleton elements get aria-busy="true" automatically.
  • pulse animation activates for users who prefer reduced motion.
  • Skeleton pseudo-elements have pointer-events: none.

On this page