react ~2 KB 0 deps v0.1.1 β†— GitHub β†—

@mshafiqyajid/react-skeleton

Headless skeleton hook and styled loading placeholder. Four variants (rect/line/circle/text), pulse and wave animations, configurable radius, custom base and highlight colors, repeat count with spacing, inline layout, fit-content sizing, and reduced-motion support. Zero dependencies.

Playground #

Props
TSX
import { SkeletonStyled } from "@mshafiqyajid/react-skeleton/styled";
import "@mshafiqyajid/react-skeleton/styles.css";

<SkeletonStyled />

Install #

npm install @mshafiqyajid/react-skeleton

Quick start #

import { SkeletonStyled } from "@mshafiqyajid/react-skeleton/styled";
import "@mshafiqyajid/react-skeleton/styles.css";

// Rectangle placeholder
<SkeletonStyled width="100%" height={20} />

// Circle avatar
<SkeletonStyled variant="circle" width="2.5rem" height="2.5rem" />

// Text block (3 lines, last at 60%)
<SkeletonStyled variant="text" lines={3} lastLineWidth="60%" />

// Wave shimmer
<SkeletonStyled animation="wave" width="100%" height={80} />

Card skeleton composition #

import { SkeletonStyled } from "@mshafiqyajid/react-skeleton/styled";
import "@mshafiqyajid/react-skeleton/styles.css";

function CardSkeleton() {
  return (
    <div style={{ display: "flex", gap: "1rem", alignItems: "flex-start" }}>
      <SkeletonStyled variant="circle" width="2.5rem" height="2.5rem" />
      <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: "0.5rem" }}>
        <SkeletonStyled variant="line" height="0.875rem" width="60%" />
        <SkeletonStyled variant="line" height="0.75rem" width="40%" />
        <SkeletonStyled variant="text" lines={3} />
      </div>
    </div>
  );
}

Headless #

import { useSkeleton } from "@mshafiqyajid/react-skeleton";

function MySkeleton() {
  const { skeletonProps } = useSkeleton();
  return (
    <div {...skeletonProps} className="my-skeleton">
      {/* your placeholder shape */}
    </div>
  );
}

Repeated skeletons #

// Stack 4 line skeletons with 12px gap
<SkeletonStyled variant="line" count={4} spacing={12} />

// Inline badges
<SkeletonStyled variant="rect" count={3} inline spacing={8} width={64} height={24} radius="full" />

// Disable animation for all items in the group
<SkeletonStyled count={3} enableAnimation={false} />

Custom colors #

Override the base skeleton color and the wave shimmer highlight with baseColor and highlightColor. Both accept any valid CSS color string and set the underlying CSS variables (--rsk-bg and --rsk-wave-highlight) inline so overrides are scoped to that specific element.

{/* Blue-tinted skeleton β€” useful for matching a card's background */}
<SkeletonStyled
  animation="wave"
  width="100%"
  height={80}
  baseColor="#bfdbfe"
  highlightColor="#dbeafe"
/>

{/* Warm tone */}
<SkeletonStyled
  animation="wave"
  variant="text"
  lines={3}
  baseColor="#fde68a"
  highlightColor="#fef3c7"
/>

Custom border radius #

The radius prop covers the preset scale ("none" β†’ "full"). For anything in between, pass borderRadius with any CSS value β€” it overrides the preset via --rsk-custom-radius.

{/* Pill badge skeleton */}
<SkeletonStyled width={80} height={24} borderRadius="20px" />

{/* Slightly rounded card */}
<SkeletonStyled variant="rect" width="100%" height={120} borderRadius={6} />

fitContent #

By default the skeleton expands to fill available space. Set fitContent to size the element to its natural content dimensions instead β€” useful when wrapping a skeleton around a specific element shape inside a flex container.

<div style={{ display: "flex", gap: "0.5rem" }}>
  <SkeletonStyled variant="rect" fitContent width={48} height={48} />
  <SkeletonStyled variant="text" fitContent lines={2} />
</div>

CSS variables #

:root {
  --rsk-bg: #e4e4e7;
  --rsk-wave-highlight: rgba(255, 255, 255, 0.7);
  --rsk-radius-sm: 4px;
  --rsk-radius-md: 8px;
  --rsk-radius-lg: 12px;
  --rsk-duration-pulse: 1.4s;
  --rsk-duration-wave: 1.6s;
}

API #

PropTypeDefaultDescription
variant"rect" | "line" | "circle" | "text""rect"Shape variant
animation"pulse" | "wave" | "none""pulse"Animation style
widthstring | numberβ€”Width (e.g. "100%", 200, "12rem")
heightstring | numberβ€”Height (e.g. 20, "1rem")
radius"none" | "sm" | "md" | "lg" | "full""sm"Border radius preset
borderRadiusstring | numberβ€”Custom border-radius, overrides radius preset
linesnumber3Number of lines (text variant only)
lastLineWidthstring"60%"Width of last line (text variant only)
countnumber1Render N skeletons stacked; wraps in .rsk-group
spacingnumber8Gap in px between items when count > 1
inlinebooleanfalseUse inline-block display; group becomes inline-flex
baseColorstringβ€”Override skeleton base color (sets --rsk-bg)
highlightColorstringβ€”Override shimmer highlight color (sets --rsk-wave-highlight)
enableAnimationbooleantrueSet to false to disable animation (same as animation="none")
fitContentbooleanfalseSize skeleton to its natural content dimensions
classNamestringβ€”Extra class on root
styleCSSPropertiesβ€”Inline style override
Edit this page on GitHub