react-ez-skeleton

Lightweight, accessible, and themeable skeleton loading components for React. Built with SSR, reduced motion, and testing DX in mind.

npm install react-ez-skeleton

Getting Started

Add skeleton loaders to your React app in seconds.

1. Install

npm install react-ez-skeleton

2. Import and use

import { Skeleton, SkeletonText, SkeletonCircle } from "react-ez-skeleton";

function ProfileCard() {
  return (
    <div>
      <SkeletonCircle size={64} dataTestId="avatar" />
      <SkeletonText lines={2} width="80%" dataTestId="name" />
    </div>
  );
}

3. Test with data-testid

Each component accepts a dataTestId prop that maps to data-testid for easy testing. SkeletonText automatically appends line indexes (-0, -1, …).

import { render, screen } from "@testing-library/react";
import { Skeleton } from "react-ez-skeleton";

test("renders skeleton with test ID", () => {
  render(<Skeleton dataTestId="loading-avatar" />);
  expect(screen.getByTestId("loading-avatar")).toBeInTheDocument();
});

Live Examples

Interactive demos with dark mode and reduced motion support.

Basic Skeletons

<Skeleton width={200} height={20} />
<SkeletonText lines={3} />
<SkeletonCircle size={48} />

Customized SkeletonText with Random Widths

<SkeletonText
  lines={4}
  lineHeight={20}
  gap={12}
  randomizeLineWidths
  randomizeMin={60}
  randomizeMax={95}
  dataTestId="random-text"
/>

Theming via CSS Variables

<div style={{
  "--ez-skeleton-color-start": "#fef3c7",
  "--ez-skeleton-color-middle": "#fde68a",
  "--ez-skeleton-color-end": "#fef3c7",
}}>
  <Skeleton width={180} height={16} />
</div>

Props & API Reference

Detailed props for each component.

Skeleton

PropTypeDefaultDescription
widthstring | number"100%"Width of the skeleton
heightstring | number16Height of the skeleton
radiusstring | number4Border radius
classNamestringCustom class
styleReact.CSSPropertiesInline styles
animatebooleantrueEnable shimmer animation
respectReducedMotionbooleantrueRespects OS motion settings
ariaHiddenbooleantrueAccessibility: hide from screen readers
injectStylesbooleantrueAuto-inject required styles
dataTestIdstringMaps to data-testid for testing
<Skeleton
  width={200}
  height={20}
  radius={8}
  disableAnimation={false}
  dataTestId="title-skeleton"
/>

SkeletonText

PropTypeDefaultDescription
linesnumber3Number of lines
lineHeightstring | number16Height of each line
gapstring | number8Gap between lines
widthstring | number"100%"Width of the last line (full lines are 100%)
radiusstring | number4Border radius per line
randomizeLineWidthsbooleanfalseEnable randomized line widths
randomizeMinnumber60Min percentage for random widths
randomizeMaxnumber100Max percentage for random widths
randomizeSeednumberSeed for deterministic randomness
lineWidths(number | string)[]Explicit widths per line
aria-hiddenbooleantrueAccessibility: hide from screen readers
animatebooleantrueEnable shimmer animation
respectReducedMotionbooleantrueRespects OS motion settings
injectStylesbooleantrueAuto-inject required styles
dataTestIdstringMaps to data-testid; lines are suffixed with -0, -1, …
<SkeletonText
  lines={4}
  lineHeight={20}
  gap={12}
  width="80%"
  dataTestId="bio-skeleton"
/>

SkeletonCircle

PropTypeDefaultDescription
sizestring | number40Width and height (circle)
classNamestringCustom class
styleReact.CSSPropertiesInline styles
animatebooleantrueEnable shimmer animation
respectReducedMotionbooleantrueRespects OS motion settings
ariaHiddenbooleantrueAccessibility: hide from screen readers
injectStylesbooleantrueAuto-inject required styles
dataTestIdstringMaps to data-testid for testing
<SkeletonCircle
  size={64}
  dataTestId="avatar-skeleton"
/>

Theming & Accessibility

Customize colors and respect user preferences.

CSS Variables

Override the default shimmer colors and animation using CSS variables. Wrap skeletons in a container with custom variables to theme per-component.

:root {
  --ez-skeleton-color-start: #f2f2f2;
  --ez-skeleton-color-middle: #e6e6e6;
  --ez-skeleton-color-end: #f2f2f2;
  --ez-skeleton-animation: react-ez-skeleton-pulse 1.4s ease-in-out infinite;
}

.dark {
  --ez-skeleton-color-start: #374151;
  --ez-skeleton-color-middle: #4b5563;
  --ez-skeleton-color-end: #374151;
}
Purple theme example:

Reduced Motion

Skeletons automatically respect prefers-reduced-motion. You can also disable animations per-instance with the disableAnimation prop.

@media (prefers-reduced-motion: reduce) {
  :root {
    --ez-skeleton-animation: none;
  }
}
With reduced motion (no animation):

Accessibility

  • Skeletons are aria-hidden="true" by default to hide from screen readers.
  • Use dataTestId for testing; it maps to data-testid.
  • Reduced motion is respected automatically.
  • Components are SSR-safe with no runtime dependencies beyond React.

Comparison

How react-ez-skeleton stacks up against alternatives.

Featurereact-ez-skeletonreact-loading-skeleton@mui/material Skeleton
Bundle size~1.75 kB (gzip)~3.3 kB (gzip)Part of MUI (~large)
Theming via CSS vars❌ (inline styles)✅ (MUI theme)
Reduced motion support✅ (built-in)
data-testid / testing DX✅ (dataTestId prop)❌ (manual)❌ (manual)
SSR safe
Zero dependencies❌ (MUI deps)
SkeletonText with random widths✅ (built-in)
Circle component❌ (manual borderRadius)

react-ez-skeleton focuses on developer experience, minimal bundle size, and modern React patterns without requiring a design system.

Conclusion

Ready to ship faster with better loading UX.

react-ez-skeleton gives you lightweight, accessible, and themeable skeleton loaders with zero dependencies and excellent testing DX.

Star the repo, report issues, and contribute to make loading states better for everyone.